在介绍SwitchButton之前,先来看一下系统Button是如何实现的。源码如下:

  1. @RemoteView
  2. public class Button extends TextView {
  3. public Button(Context context) {
  4. this(context, null);
  5. }
  6. public Button(Context context, AttributeSet attrs) {
  7. this(context, attrs, com.android.internal.R.attr.buttonStyle);
  8. }
  9. public Button(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  14. super.onInitializeAccessibilityEvent(event);
  15. event.setClassName(Button. class.getName());
  16. }
  17. @Override
  18. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  19. super.onInitializeAccessibilityNodeInfo(info);
  20. info.setClassName(Button. class.getName());
  21. }
  22. }
@RemoteView
public class Button extends TextView {
public Button(Context context) {
this(context, null);
} public Button(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.buttonStyle);
} public Button(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(Button. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Button. class.getName());
}
}
  是直接继承于TextView,所不同的是在构造方法中添加了Button的样式,并且在初始化可见性方面交由Button类自己来处理。虽然Button的实现比较简单,但是它的子类并不是这样。看一下:
  直接子类只有有一个,CompoundButton。它是一个抽象类,而实现这个类的控件正是CheckBoxRadioButtonSwitchToggleButton这四个,所以先重点说一下它。源码如下:

  1. /**
  2. * <p>
  3. * A button with two states, checked and unchecked. When the button is pressed
  4. * or clicked, the state changes automatically.
  5. * </p>
  6. *
  7. * <p><strong>XML attributes </strong></p>
  8. * <p>
  9. * See {@link android.R.styleable#CompoundButton
  10. * CompoundButton Attributes}, {@link android.R.styleable#Button Button
  11. * Attributes}, {@link android.R.styleable#TextView TextView Attributes}, {@link
  12. * android.R.styleable #View View Attributes}
  13. * </p>
  14. */
  15. public abstract class CompoundButton extends Button implements Checkable {
  16. private boolean mChecked ;
  17. private int mButtonResource ;
  18. private boolean mBroadcasting ;
  19. private Drawable mButtonDrawable;
  20. private OnCheckedChangeListener mOnCheckedChangeListener;
  21. private OnCheckedChangeListener mOnCheckedChangeWidgetListener ;
  22. private static final int[] CHECKED_STATE_SET = {
  23. R.attr.state_checked
  24. };
  25. public CompoundButton(Context context) {
  26. this(context, null);
  27. }
  28. public CompoundButton(Context context, AttributeSet attrs) {
  29. this(context, attrs, 0);
  30. }
  31. public CompoundButton(Context context, AttributeSet attrs, int defStyle) {
  32. super(context, attrs, defStyle);
  33. TypedArray a =
  34. context.obtainStyledAttributes(
  35. attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0);
  36. Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
  37. if (d != null ) {
  38. setButtonDrawable(d);
  39. }
  40. boolean checked = a
  41. .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
  42. setChecked(checked);
  43. a.recycle();
  44. }
  45. public void toggle() {
  46. setChecked(! mChecked);
  47. }
  48. @Override
  49. public boolean performClick() {
  50. /*
  51. * XXX: These are tiny, need some surrounding 'expanded touch area',
  52. * which will need to be implemented in Button if we only override
  53. * performClick()
  54. */
  55. /* When clicked, toggle the state */
  56. toggle();
  57. return super .performClick();
  58. }
  59. @ViewDebug.ExportedProperty
  60. public boolean isChecked() {
  61. return mChecked ;
  62. }
  63. /**
  64. * <p>Changes the checked state of this button.</p>
  65. *
  66. * @param checked true to check the button, false to uncheck it
  67. */
  68. public void setChecked(boolean checked) {
  69. if (mChecked != checked) {
  70. mChecked = checked;
  71. refreshDrawableState();
  72. notifyViewAccessibilityStateChangedIfNeeded(
  73. AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED );
  74. // Avoid infinite recursions if setChecked() is called from a listener
  75. if (mBroadcasting ) {
  76. return;
  77. }
  78. mBroadcasting = true ;
  79. if (mOnCheckedChangeListener != null) {
  80. mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
  81. }
  82. if (mOnCheckedChangeWidgetListener != null) {
  83. mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
  84. }
  85. mBroadcasting = false ;
  86. }
  87. }
  88. /**
  89. * Register a callback to be invoked when the checked state of this button
  90. * changes.
  91. *
  92. * @param listener the callback to call on checked state change
  93. */
  94. public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
  95. mOnCheckedChangeListener = listener;
  96. }
  97. /**
  98. * Register a callback to be invoked when the checked state of this button
  99. * changes. This callback is used for internal purpose only.
  100. *
  101. * @param listener the callback to call on checked state change
  102. * @hide
  103. */
  104. void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) {
  105. mOnCheckedChangeWidgetListener = listener;
  106. }
  107. /**
  108. * Interface definition for a callback to be invoked when the checked state
  109. * of a compound button changed.
  110. */
  111. public static interface OnCheckedChangeListener {
  112. /**
  113. * Called when the checked state of a compound button has changed.
  114. *
  115. * @param buttonView The compound button view whose state has changed.
  116. * @param isChecked  The new checked state of buttonView.
  117. */
  118. void onCheckedChanged(CompoundButton buttonView, boolean isChecked);
  119. }
  120. /**
  121. * Set the background to a given Drawable, identified by its resource id.
  122. *
  123. * @param resid the resource id of the drawable to use as the background
  124. */
  125. public void setButtonDrawable(int resid) {
  126. if (resid != 0 && resid == mButtonResource ) {
  127. return;
  128. }
  129. mButtonResource = resid;
  130. Drawable d = null;
  131. if (mButtonResource != 0) {
  132. d = getResources().getDrawable(mButtonResource );
  133. }
  134. setButtonDrawable(d);
  135. }
  136. /**
  137. * Set the background to a given Drawable
  138. *
  139. * @param d The Drawable to use as the background
  140. */
  141. public void setButtonDrawable(Drawable d) {
  142. if (d != null ) {
  143. if (mButtonDrawable != null) {
  144. mButtonDrawable.setCallback(null);
  145. unscheduleDrawable( mButtonDrawable);
  146. }
  147. d.setCallback( this);
  148. d.setVisible(getVisibility() == VISIBLE, false);
  149. mButtonDrawable = d;
  150. setMinHeight(mButtonDrawable .getIntrinsicHeight());
  151. }
  152. refreshDrawableState();
  153. }
  154. @Override
  155. public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  156. super.onInitializeAccessibilityEvent(event);
  157. event.setClassName(CompoundButton.class .getName());
  158. event.setChecked( mChecked);
  159. }
  160. @Override
  161. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  162. super.onInitializeAccessibilityNodeInfo(info);
  163. info.setClassName(CompoundButton.class .getName());
  164. info.setCheckable( true);
  165. info.setChecked( mChecked);
  166. }
  167. @Override
  168. public int getCompoundPaddingLeft() {
  169. int padding = super.getCompoundPaddingLeft();
  170. if (!isLayoutRtl()) {
  171. final Drawable buttonDrawable = mButtonDrawable;
  172. if (buttonDrawable != null) {
  173. padding += buttonDrawable.getIntrinsicWidth();
  174. }
  175. }
  176. return padding;
  177. }
  178. @Override
  179. public int getCompoundPaddingRight() {
  180. int padding = super.getCompoundPaddingRight();
  181. if (isLayoutRtl()) {
  182. final Drawable buttonDrawable = mButtonDrawable;
  183. if (buttonDrawable != null) {
  184. padding += buttonDrawable.getIntrinsicWidth();
  185. }
  186. }
  187. return padding;
  188. }
  189. /**
  190. * @hide
  191. */
  192. @Override
  193. public int getHorizontalOffsetForDrawables() {
  194. final Drawable buttonDrawable = mButtonDrawable ;
  195. return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0;
  196. }
  197. @Override
  198. protected void onDraw(Canvas canvas) {
  199. super.onDraw(canvas);
  200. final Drawable buttonDrawable = mButtonDrawable ;
  201. if (buttonDrawable != null) {
  202. final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK ;
  203. final int drawableHeight = buttonDrawable.getIntrinsicHeight();
  204. final int drawableWidth = buttonDrawable.getIntrinsicWidth();
  205. int top = 0;
  206. switch (verticalGravity) {
  207. case Gravity.BOTTOM :
  208. top = getHeight() - drawableHeight;
  209. break;
  210. case Gravity.CENTER_VERTICAL :
  211. top = (getHeight() - drawableHeight) / 2;
  212. break;
  213. }
  214. int bottom = top + drawableHeight;
  215. int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
  216. int right = isLayoutRtl() ? getWidth() : drawableWidth;
  217. buttonDrawable.setBounds(left, top, right, bottom);
  218. buttonDrawable.draw(canvas);
  219. }
  220. }
  221. @Override
  222. protected int[] onCreateDrawableState(int extraSpace) {
  223. final int [] drawableState = super.onCreateDrawableState(extraSpace + 1);
  224. if (isChecked()) {
  225. mergeDrawableStates(drawableState, CHECKED_STATE_SET);
  226. }
  227. return drawableState;
  228. }
  229. @Override
  230. protected void drawableStateChanged() {
  231. super.drawableStateChanged();
  232. if (mButtonDrawable != null) {
  233. int[] myDrawableState = getDrawableState();
  234. // Set the state of the Drawable
  235. mButtonDrawable.setState(myDrawableState);
  236. invalidate();
  237. }
  238. }
  239. @Override
  240. protected boolean verifyDrawable(Drawable who) {
  241. return super .verifyDrawable(who) || who == mButtonDrawable;
  242. }
  243. @Override
  244. public void jumpDrawablesToCurrentState() {
  245. super.jumpDrawablesToCurrentState();
  246. if (mButtonDrawable != null) mButtonDrawable.jumpToCurrentState();
  247. }
  248. static class SavedState extends BaseSavedState {
  249. boolean checked ;
  250. /**
  251. * Constructor called from {@link CompoundButton#onSaveInstanceState()}
  252. */
  253. SavedState(Parcelable superState) {
  254. super(superState);
  255. }
  256. /**
  257. * Constructor called from {@link #CREATOR}
  258. */
  259. private SavedState(Parcel in) {
  260. super(in);
  261. checked = (Boolean)in.readValue( null);
  262. }
  263. @Override
  264. public void writeToParcel(Parcel out, int flags) {
  265. super.writeToParcel(out, flags);
  266. out.writeValue( checked);
  267. }
  268. @Override
  269. public String toString() {
  270. return "CompoundButton.SavedState{"
  271. + Integer.toHexString(System.identityHashCode(this))
  272. + " checked=" + checked + "}" ;
  273. }
  274. public static final Parcelable.Creator<SavedState> CREATOR
  275. = new Parcelable.Creator<SavedState>() {
  276. public SavedState createFromParcel(Parcel in) {
  277. return new SavedState(in);
  278. }
  279. public SavedState[] newArray(int size) {
  280. return new SavedState[size];
  281. }
  282. };
  283. }
  284. @Override
  285. public Parcelable onSaveInstanceState() {
  286. // Force our ancestor class to save its state
  287. setFreezesText( true);
  288. Parcelable superState = super.onSaveInstanceState();
  289. SavedState ss = new SavedState(superState);
  290. ss. checked = isChecked();
  291. return ss;
  292. }
  293. @Override
  294. public void onRestoreInstanceState(Parcelable state) {
  295. SavedState ss = (SavedState) state;
  296. super.onRestoreInstanceState(ss.getSuperState());
  297. setChecked(ss. checked);
  298. requestLayout();
  299. }
  300. }
/**
* <p>
* A button with two states, checked and unchecked. When the button is pressed
* or clicked, the state changes automatically.
* </p>
*
* <p><strong>XML attributes </strong></p>
* <p>
* See {@link android.R.styleable#CompoundButton
* CompoundButton Attributes}, {@link android.R.styleable#Button Button
* Attributes}, {@link android.R.styleable#TextView TextView Attributes}, {@link
* android.R.styleable #View View Attributes}
* </p>
*/
public abstract class CompoundButton extends Button implements Checkable {
private boolean mChecked ;
private int mButtonResource ;
private boolean mBroadcasting ;
private Drawable mButtonDrawable;
private OnCheckedChangeListener mOnCheckedChangeListener;
private OnCheckedChangeListener mOnCheckedChangeWidgetListener ; private static final int[] CHECKED_STATE_SET = {
R.attr.state_checked
}; public CompoundButton(Context context) {
this(context, null);
} public CompoundButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public CompoundButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray a =
context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0); Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null ) {
setButtonDrawable(d);
} boolean checked = a
.getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked); a.recycle();
} public void toggle() {
setChecked(! mChecked);
} @Override
public boolean performClick() {
/*
* XXX: These are tiny, need some surrounding 'expanded touch area',
* which will need to be implemented in Button if we only override
* performClick()
*/ /* When clicked, toggle the state */
toggle();
return super .performClick();
} @ViewDebug.ExportedProperty
public boolean isChecked() {
return mChecked ;
} /**
* <p>Changes the checked state of this button.</p>
*
* @param checked true to check the button, false to uncheck it
*/
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED ); // Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting ) {
return;
} mBroadcasting = true ;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
} mBroadcasting = false ;
}
} /**
* Register a callback to be invoked when the checked state of this button
* changes.
*
* @param listener the callback to call on checked state change
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
} /**
* Register a callback to be invoked when the checked state of this button
* changes. This callback is used for internal purpose only.
*
* @param listener the callback to call on checked state change
* @hide
*/
void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) {
mOnCheckedChangeWidgetListener = listener;
} /**
* Interface definition for a callback to be invoked when the checked state
* of a compound button changed.
*/
public static interface OnCheckedChangeListener {
/**
* Called when the checked state of a compound button has changed.
*
* @param buttonView The compound button view whose state has changed.
* @param isChecked The new checked state of buttonView.
*/
void onCheckedChanged(CompoundButton buttonView, boolean isChecked);
} /**
* Set the background to a given Drawable, identified by its resource id.
*
* @param resid the resource id of the drawable to use as the background
*/
public void setButtonDrawable(int resid) {
if (resid != 0 && resid == mButtonResource ) {
return;
} mButtonResource = resid; Drawable d = null;
if (mButtonResource != 0) {
d = getResources().getDrawable(mButtonResource );
}
setButtonDrawable(d);
} /**
* Set the background to a given Drawable
*
* @param d The Drawable to use as the background
*/
public void setButtonDrawable(Drawable d) {
if (d != null ) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable( mButtonDrawable);
}
d.setCallback( this);
d.setVisible(getVisibility() == VISIBLE, false);
mButtonDrawable = d;
setMinHeight(mButtonDrawable .getIntrinsicHeight());
} refreshDrawableState();
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(CompoundButton.class .getName());
event.setChecked( mChecked);
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(CompoundButton.class .getName());
info.setCheckable( true);
info.setChecked( mChecked);
} @Override
public int getCompoundPaddingLeft() {
int padding = super.getCompoundPaddingLeft();
if (!isLayoutRtl()) {
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
padding += buttonDrawable.getIntrinsicWidth();
}
}
return padding;
} @Override
public int getCompoundPaddingRight() {
int padding = super.getCompoundPaddingRight();
if (isLayoutRtl()) {
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
padding += buttonDrawable.getIntrinsicWidth();
}
}
return padding;
} /**
* @hide
*/
@Override
public int getHorizontalOffsetForDrawables() {
final Drawable buttonDrawable = mButtonDrawable ;
return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0;
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); final Drawable buttonDrawable = mButtonDrawable ;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK ;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth(); int top = 0;
switch (verticalGravity) {
case Gravity.BOTTOM :
top = getHeight() - drawableHeight;
break;
case Gravity.CENTER_VERTICAL :
top = (getHeight() - drawableHeight) / 2;
break;
}
int bottom = top + drawableHeight;
int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
int right = isLayoutRtl() ? getWidth() : drawableWidth; buttonDrawable.setBounds(left, top, right, bottom);
buttonDrawable.draw(canvas);
}
} @Override
protected int[] onCreateDrawableState(int extraSpace) {
final int [] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
} @Override
protected void drawableStateChanged() {
super.drawableStateChanged(); if (mButtonDrawable != null) {
int[] myDrawableState = getDrawableState(); // Set the state of the Drawable
mButtonDrawable.setState(myDrawableState); invalidate();
}
} @Override
protected boolean verifyDrawable(Drawable who) {
return super .verifyDrawable(who) || who == mButtonDrawable;
} @Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (mButtonDrawable != null) mButtonDrawable.jumpToCurrentState();
} static class SavedState extends BaseSavedState {
boolean checked ; /**
* Constructor called from {@link CompoundButton#onSaveInstanceState()}
*/
SavedState(Parcelable superState) {
super(superState);
} /**
* Constructor called from {@link #CREATOR}
*/
private SavedState(Parcel in) {
super(in);
checked = (Boolean)in.readValue( null);
} @Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue( checked);
} @Override
public String toString() {
return "CompoundButton.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " checked=" + checked + "}" ;
} public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
} public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
} @Override
public Parcelable onSaveInstanceState() {
// Force our ancestor class to save its state
setFreezesText( true);
Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss. checked = isChecked();
return ss;
} @Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss. checked);
requestLayout();
}
}

先从构造方法开始,在构造方法中,

  1. public CompoundButton(Context context, AttributeSet attrs, int defStyle) {
  2. super(context, attrs, defStyle);
  3. TypedArray a =
  4. context.obtainStyledAttributes(
  5. attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0);
  6. Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
  7. if (d != null ) {
  8. setButtonDrawable(d);
  9. }
  10. boolean checked = a
  11. .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
  12. setChecked(checked);
  13. a.recycle();
  14. }
 public CompoundButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray a =
context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0); Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null ) {
setButtonDrawable(d);
} boolean checked = a
.getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked); a.recycle();
}

先是从attrs中读取定义的属性,一个是Drawable用于设置背景;一个是布尔类型变量用于判断是否check过。设置背景使用的是setButtonDrawable()方法,代码如下:

  1. /**
  2. * Set the background to a given Drawable
  3. *
  4. * @param d The Drawable to use as the background
  5. */
  6. public void setButtonDrawable(Drawable d) {
  7. if (d != null ) {
  8. if (mButtonDrawable != null) {
  9. mButtonDrawable.setCallback(null);
  10. unscheduleDrawable( mButtonDrawable);
  11. }
  12. d.setCallback( this);
  13. d.setVisible(getVisibility() == VISIBLE, false);
  14. mButtonDrawable = d;
  15. setMinHeight(mButtonDrawable .getIntrinsicHeight());
  16. }
  17. refreshDrawableState();
  18. }
/**
* Set the background to a given Drawable
*
* @param d The Drawable to use as the background
*/
public void setButtonDrawable(Drawable d) {
if (d != null ) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable( mButtonDrawable);
}
d.setCallback( this);
d.setVisible(getVisibility() == VISIBLE, false);
mButtonDrawable = d;
setMinHeight(mButtonDrawable .getIntrinsicHeight());
} refreshDrawableState();
}

这个方法写的就比较完善,可以作为一个学习的典范。首先判断传递过来的Drawable是否为空,如果不为空并且默认的Drawable也不为空,那么取消默认Drawable的callback,然后调用unscheduleDrawable方法。这个方法代码如下:

  1. /**
  2. * Unschedule any events associated with the given Drawable.  This can be
  3. * used when selecting a new Drawable into a view, so that the previous
  4. * one is completely unscheduled.
  5. *
  6. * @param who The Drawable to unschedule.
  7. *
  8. * @see #drawableStateChanged
  9. */
  10. public void unscheduleDrawable(Drawable who) {
  11. if (mAttachInfo != null && who != null) {
  12. mAttachInfo.mViewRootImpl .mChoreographer.removeCallbacks(
  13. Choreographer.CALLBACK_ANIMATION, null, who);
  14. }
  15. }
 /**
* Unschedule any events associated with the given Drawable. This can be
* used when selecting a new Drawable into a view, so that the previous
* one is completely unscheduled.
*
* @param who The Drawable to unschedule.
*
* @see #drawableStateChanged
*/
public void unscheduleDrawable(Drawable who) {
if (mAttachInfo != null && who != null) {
mAttachInfo.mViewRootImpl .mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, null, who);
}
}

从方法注释中可以看出它的用途,正是更换Drawable时候使用的。接下来开始重新设置Drawable,包括回调、可见性、最小高度。最后调用refreshDrawableState()方法,这个是View类的方法,用于更新Drawable状态。

  然后再回过头看一下setChecked(checked)方法,这个用于设置check,也就是button的点击状态。代码如下:
  1. /**
  2. * <p>Changes the checked state of this button.</p>
  3. *
  4. * @param checked true to check the button, false to uncheck it
  5. */
  6. public void setChecked( boolean checked) {
  7. if (mChecked != checked) {
  8. mChecked = checked;
  9. refreshDrawableState();
  10. notifyViewAccessibilityStateChangedIfNeeded(
  11. AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED );
  12. // Avoid infinite recursions if setChecked() is called from a listener
  13. if (mBroadcasting ) {
  14. return;
  15. }
  16. mBroadcasting = true ;
  17. if (mOnCheckedChangeListener != null) {
  18. mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
  19. }
  20. if (mOnCheckedChangeWidgetListener != null) {
  21. mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
  22. }
  23. mBroadcasting = false ;
  24. }
  25. }
/**
* <p>Changes the checked state of this button.</p>
*
* @param checked true to check the button, false to uncheck it
*/
public void setChecked( boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED ); // Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting ) {
return;
} mBroadcasting = true ;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
}
mBroadcasting = false ;
}
}
  在这个方法中多出了一个接口,这个接口真是check的一个回调接口,代码如下:
  1. /**
  2. * Interface definition for a callback to be invoked when the checked state
  3. * of a compound button changed.
  4. */
  5. public static interface OnCheckedChangeListener {
  6. /**
  7. * Called when the checked state of a compound button has changed.
  8. *
  9. * @param buttonView The compound button view whose state has changed.
  10. * @param isChecked  The new checked state of buttonView.
  11. */
  12. void onCheckedChanged(CompoundButton buttonView, boolean isChecked);
  13. }
/**
* Interface definition for a callback to be invoked when the checked state
* of a compound button changed.
*/
public static interface OnCheckedChangeListener {
/**
* Called when the checked state of a compound button has changed.
*
* @param buttonView The compound button view whose state has changed.
* @param isChecked The new checked state of buttonView.
*/
void onCheckedChanged(CompoundButton buttonView, boolean isChecked);
}
  这种回调接口在Android中处处可见,之前的文章也有介绍过。但是在上面的方法,它使用了一个mBroadcasting变量,进而巧妙地避免了重复递归的问题,大家自己感受一下。
  然后就是ondraw()方法了,把之前的drawable画出来。代码如下:
  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. final Drawable buttonDrawable = mButtonDrawable ;
  5. if (buttonDrawable != null) {
  6. final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK ;
  7. final int drawableHeight = buttonDrawable.getIntrinsicHeight();
  8. final int drawableWidth = buttonDrawable.getIntrinsicWidth();
  9. int top = 0;
  10. switch (verticalGravity) {
  11. case Gravity.BOTTOM :
  12. top = getHeight() - drawableHeight;
  13. break;
  14. case Gravity.CENTER_VERTICAL :
  15. top = (getHeight() - drawableHeight) / 2;
  16. break;
  17. }
  18. int bottom = top + drawableHeight;
  19. int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
  20. int right = isLayoutRtl() ? getWidth() : drawableWidth;
  21. buttonDrawable.setBounds(left, top, right, bottom);
  22. buttonDrawable.draw(canvas);
  23. }
  24. }
  @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); final Drawable buttonDrawable = mButtonDrawable ;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK ;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth(); int top = 0;
switch (verticalGravity) {
case Gravity.BOTTOM :
top = getHeight() - drawableHeight;
break;
case Gravity.CENTER_VERTICAL :
top = (getHeight() - drawableHeight) / 2;
break;
}
int bottom = top + drawableHeight;
int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
int right = isLayoutRtl() ? getWidth() : drawableWidth; buttonDrawable.setBounds(left, top, right, bottom);
buttonDrawable.draw(canvas);
}
}
  看得出来,在onDrawable()方法中,最主要的部分还是如何确定上下左右四个参数。确定完后就可以画出来了。但是,CompoundButton是一个抽象类,并不能直接使用,那看一下它的子类是如何实现的:
 
1、CheckBox
  1. public class CheckBox extends CompoundButton {
  2. public CheckBox(Context context) {
  3. this(context, null);
  4. }
  5. public CheckBox(Context context, AttributeSet attrs) {
  6. this(context, attrs, com.android.internal.R.attr.checkboxStyle);
  7. }
  8. public CheckBox(Context context, AttributeSet attrs, int defStyle) {
  9. super(context, attrs, defStyle);
  10. }
  11. @Override
  12. public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  13. super.onInitializeAccessibilityEvent(event);
  14. event.setClassName(CheckBox. class.getName());
  15. }
  16. @Override
  17. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  18. super.onInitializeAccessibilityNodeInfo(info);
  19. info.setClassName(CheckBox. class.getName());
  20. }
  21. }
 public class CheckBox extends CompoundButton {
public CheckBox(Context context) {
this(context, null);
} public CheckBox(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.checkboxStyle);
} public CheckBox(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(CheckBox. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(CheckBox. class.getName());
}
}
  和Button的实现差不多,使用了一个自己的样式。并且也是重写了那两个方法。再来看一下RadioButton,
  1. public class RadioButton extends CompoundButton {
  2. public RadioButton(Context context) {
  3. this(context, null);
  4. }
  5. public RadioButton(Context context, AttributeSet attrs) {
  6. this(context, attrs, com.android.internal.R.attr.radioButtonStyle);
  7. }
  8. public RadioButton(Context context, AttributeSet attrs, int defStyle) {
  9. super(context, attrs, defStyle);
  10. }
  11. /**
  12. * {@inheritDoc}
  13. * <p>
  14. * If the radio button is already checked, this method will not toggle the radio button.
  15. */
  16. @Override
  17. public void toggle() {
  18. // we override to prevent toggle when the radio is already
  19. // checked (as opposed to check boxes widgets)
  20. if (!isChecked()) {
  21. super.toggle();
  22. }
  23. }
  24. @Override
  25. public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  26. super.onInitializeAccessibilityEvent(event);
  27. event.setClassName(RadioButton. class.getName());
  28. }
  29. @Override
  30. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  31. super.onInitializeAccessibilityNodeInfo(info);
  32. info.setClassName(RadioButton. class.getName());
  33. }
  34. }
public class RadioButton extends CompoundButton {

    public RadioButton(Context context) {
this(context, null);
} public RadioButton(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.radioButtonStyle);
} public RadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} /**
* {@inheritDoc}
* <p>
* If the radio button is already checked, this method will not toggle the radio button.
*/
@Override
public void toggle() {
// we override to prevent toggle when the radio is already
// checked (as opposed to check boxes widgets)
if (!isChecked()) {
super.toggle();
}
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(RadioButton. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(RadioButton. class.getName());
}
}

和CheckBox实现差不多,区别在于多重写了一个方法,用于防止按钮被重复点击。另外还有ToggleButton以及Switch,前者实现也比较简单,后者稍微麻烦了一些,感兴趣可以自己分析。

  最后切入正题,看看滑动Button要如何实现呢?首先看一下效果图:
 图1-1
  
 图1-2
  图1-1所示的滑动Button实现的思路是这样的,背景图片有开和关的文字,一个按钮在其上面左右滑动,遮住相应的部分,使其在一个位置时候只能看到一个开关。
  如图1-3,在实现的时候,先画一个开关背景图片只,然后在其上面画一个按钮,滑动开关的时候对上面的按钮进行处理即可。
  准备:
 
    1、按钮图片
       
      
    2、背景图片       
       
 编码:
    在自定义滑动按钮控件的时候,可以有多种选择,可以继承于Button,也可以继承于Button的子类,也可以继承于View类等。我们知道滑动按钮是一个很简单的控件,就是左右滑动改变显示内容,不需要其他的额外东西在里面,所以直接继承于View来实现即可。如果继承于系统的一些控件,那么有很多东西用不到,会造成浪费。
    1、定义一个类继承于View,初始化构造方法,在构造方法中加载图片及其信息。
    2、重写onMeasure()方法,计算控件的大小。
    3、重写onTouchEvent()方法,对滑动事件进行判别处理。
    4、定义接口,实现回调。
    5、重写onDraw()方法,动态画出按钮。
代码如下:
  1. /**
  2. *
  3. */
  4. package com.kince.slidebutton;
  5. import android.content.Context;
  6. import android.graphics.Bitmap;
  7. import android.graphics.BitmapFactory;
  8. import android.graphics.Canvas;
  9. import android.util.AttributeSet;
  10. import android.util.Log;
  11. import android.view.MotionEvent;
  12. import android.view.View;
  13. /**
  14. * @author kince
  15. * @category 左右手势滑动button
  16. * @serial 1.0.0
  17. * @since 2014.5.17
  18. * @see http://blog.csdn.net/wangjinyu501
  19. *
  20. */
  21. public class SlideButton extends View {
  22. private Bitmap slideBitMap;// 滑动图片
  23. private Bitmap switchBitMap;// 背景图片
  24. private int slideBitMapWidth;// 滑动图片宽度
  25. private int switchBitMapWidth;// 背景图片宽度
  26. private int switchBitMapHeight;// 背景图片高度
  27. private boolean currentState;// 开关状态
  28. private boolean isSliding = false; // 是否正在滑动中
  29. private int currentX; // 当前开关的位置
  30. private OnToggleStateChangedListener mChangedListener;// 回调接口
  31. /**
  32. * @param context
  33. *            在java代码中直接调用使用此构造方法
  34. */
  35. public SlideButton(Context context) {
  36. this(context, null);
  37. // TODO Auto-generated constructor stub
  38. }
  39. /**
  40. * @param context
  41. * @param attrs
  42. *            在xml中使用要用到这个方法
  43. */
  44. public SlideButton(Context context, AttributeSet attrs) {
  45. this(context, attrs, 0);
  46. // TODO Auto-generated constructor stub
  47. }
  48. /**
  49. * @param context
  50. * @param attrs
  51. * @param defStyleAttr
  52. *            指定一个样式
  53. */
  54. public SlideButton(Context context, AttributeSet attrs, int defStyleAttr) {
  55. super(context, attrs, defStyleAttr);
  56. initBitmap();
  57. }
  58. /**
  59. * @category 加载背景图片以及开关图片 然后获取各自的宽高
  60. *
  61. */
  62. private void initBitmap() {
  63. // TODO Auto-generated method stub
  64. slideBitMap = BitmapFactory.decodeResource(getResources(),
  65. R.drawable.slide_button_background);
  66. switchBitMap = BitmapFactory.decodeResource(getResources(),
  67. R.drawable.switch_background);
  68. slideBitMapWidth = slideBitMap.getWidth();
  69. switchBitMapWidth = switchBitMap.getWidth();
  70. switchBitMapHeight = switchBitMap.getHeight();
  71. Log.i("switchBitMapWidth", switchBitMapWidth + "");
  72. }
  73. @Override
  74. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  75. // TODO Auto-generated method stub
  76. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  77. setMeasuredDimension(switchBitMapWidth, switchBitMapHeight);// 设置控件的宽高
  78. }
  79. @Override
  80. protected void onDraw(Canvas canvas) {
  81. // 绘制button背景图片
  82. canvas.drawBitmap(switchBitMap, 0, 0, null);
  83. // 绘制滑动开关
  84. if (isSliding) {// 如果当前状态是滑动中 则动态绘制开关
  85. int dis = currentX - slideBitMapWidth / 2;
  86. if (dis < 0) {
  87. dis = 0;
  88. } else if (dis > switchBitMapWidth - slideBitMapWidth) {
  89. dis = switchBitMapWidth - slideBitMapWidth;
  90. }
  91. canvas.drawBitmap(slideBitMap, dis, 0, null);
  92. } else {
  93. if (currentState) { // 绘制开关为开的状态
  94. canvas.drawBitmap(slideBitMap, switchBitMapWidth
  95. - slideBitMapWidth, 0, null);
  96. } else { // 绘制开关为关的状态
  97. canvas.drawBitmap(slideBitMap, 0, 0, null);
  98. }
  99. }
  100. super.onDraw(canvas);
  101. }
  102. @Override
  103. public boolean onTouchEvent(MotionEvent event) {
  104. // 手势识别 判断滑动方向
  105. int action = event.getAction();
  106. switch (action) {
  107. case MotionEvent.ACTION_DOWN:
  108. isSliding = true;
  109. currentX = (int) event.getX();
  110. break;
  111. case MotionEvent.ACTION_MOVE:
  112. currentX = (int) event.getX();
  113. Log.i("currentX", currentX + "");
  114. break;
  115. case MotionEvent.ACTION_UP:
  116. isSliding = false;
  117. int bgCenter = switchBitMapWidth / 2;
  118. boolean state = currentX > bgCenter; // 改变后的状态
  119. if (state != currentState && mChangedListener != null) {// 添加回调
  120. mChangedListener.onToggleStateChanged(state);
  121. }
  122. currentState = state;
  123. break;
  124. default:
  125. break;
  126. }
  127. invalidate();
  128. return true;
  129. }
  130. public OnToggleStateChangedListener getmChangedListener() {
  131. return mChangedListener;
  132. }
  133. public void setmChangedListener(
  134. OnToggleStateChangedListener mChangedListener) {
  135. this.mChangedListener = mChangedListener;
  136. }
  137. public boolean isToggleState() {
  138. return currentState;
  139. }
  140. public void setToggleState(boolean currentState) {
  141. this.currentState = currentState;
  142. }
  143. }
/**
*
*/
package com.kince.slidebutton; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View; /**
* @author kince
* @category 左右手势滑动button
* @serial 1.0.0
* @since 2014.5.17
* @see http://blog.csdn.net/wangjinyu501
*
*/
public class SlideButton extends View { private Bitmap slideBitMap;// 滑动图片
private Bitmap switchBitMap;// 背景图片 private int slideBitMapWidth;// 滑动图片宽度
private int switchBitMapWidth;// 背景图片宽度
private int switchBitMapHeight;// 背景图片高度 private boolean currentState;// 开关状态
private boolean isSliding = false; // 是否正在滑动中 private int currentX; // 当前开关的位置 private OnToggleStateChangedListener mChangedListener;// 回调接口 /**
* @param context
* 在java代码中直接调用使用此构造方法
*/
public SlideButton(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
} /**
* @param context
* @param attrs
* 在xml中使用要用到这个方法
*/
public SlideButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
} /**
* @param context
* @param attrs
* @param defStyleAttr
* 指定一个样式
*/
public SlideButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initBitmap();
} /**
* @category 加载背景图片以及开关图片 然后获取各自的宽高
*
*/
private void initBitmap() {
// TODO Auto-generated method stub
slideBitMap = BitmapFactory.decodeResource(getResources(),
R.drawable.slide_button_background);
switchBitMap = BitmapFactory.decodeResource(getResources(),
R.drawable.switch_background);
slideBitMapWidth = slideBitMap.getWidth();
switchBitMapWidth = switchBitMap.getWidth();
switchBitMapHeight = switchBitMap.getHeight();
Log.i("switchBitMapWidth", switchBitMapWidth + "");
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(switchBitMapWidth, switchBitMapHeight);// 设置控件的宽高
} @Override
protected void onDraw(Canvas canvas) {
// 绘制button背景图片
canvas.drawBitmap(switchBitMap, 0, 0, null);
// 绘制滑动开关
if (isSliding) {// 如果当前状态是滑动中 则动态绘制开关
int dis = currentX - slideBitMapWidth / 2;
if (dis < 0) {
dis = 0;
} else if (dis > switchBitMapWidth - slideBitMapWidth) {
dis = switchBitMapWidth - slideBitMapWidth;
}
canvas.drawBitmap(slideBitMap, dis, 0, null);
} else {
if (currentState) { // 绘制开关为开的状态
canvas.drawBitmap(slideBitMap, switchBitMapWidth
- slideBitMapWidth, 0, null);
} else { // 绘制开关为关的状态
canvas.drawBitmap(slideBitMap, 0, 0, null);
}
}
super.onDraw(canvas);
} @Override
public boolean onTouchEvent(MotionEvent event) {
// 手势识别 判断滑动方向
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
isSliding = true;
currentX = (int) event.getX();
break; case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX();
Log.i("currentX", currentX + ""); break;
case MotionEvent.ACTION_UP:
isSliding = false;
int bgCenter = switchBitMapWidth / 2;
boolean state = currentX > bgCenter; // 改变后的状态
if (state != currentState && mChangedListener != null) {// 添加回调
mChangedListener.onToggleStateChanged(state);
}
currentState = state;
break;
default:
break;
}
invalidate();
return true;
} public OnToggleStateChangedListener getmChangedListener() {
return mChangedListener;
} public void setmChangedListener(
OnToggleStateChangedListener mChangedListener) {
this.mChangedListener = mChangedListener;
} public boolean isToggleState() {
return currentState;
} public void setToggleState(boolean currentState) {
this.currentState = currentState;
} }

回调接口,

  1. package com.kince.slidebutton;
  2. **
  3. * @author kince
  4. *
  5. */
  6. ublic interface OnToggleStateChangedListener {
  7. /**
  8. * @category
  9. * @param state
  10. */
  11. public void onToggleStateChanged(boolean state);
  package com.kince.slidebutton;

/**
* @author kince
*
*/
public interface OnToggleStateChangedListener { /**
* @category
* @param state
*/
public void onToggleStateChanged(boolean state); }

Activity代码,

  1. package com.kince.slidebutton;
  2. import android.support.v7.app.ActionBarActivity;
  3. import android.support.v7.app.ActionBar;
  4. import android.support.v4.app.Fragment;
  5. import android.support.v4.app.FragmentActivity;
  6. import android.os.Bundle;
  7. import android.view.LayoutInflater;
  8. import android.view.Menu;
  9. import android.view.MenuItem;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.Toast;
  13. import android.os.Build;
  14. public class MainActivity extends ActionBarActivity {
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.activity_main);
  19. if (savedInstanceState == null) {
  20. getSupportFragmentManager().beginTransaction()
  21. .add(R.id.container, new PlaceholderFragment()).commit();
  22. }
  23. }
  24. @Override
  25. public boolean onCreateOptionsMenu(Menu menu) {
  26. // Inflate the menu; this adds items to the action bar if it is present.
  27. getMenuInflater().inflate(R.menu.main, menu);
  28. return true;
  29. }
  30. @Override
  31. public boolean onOptionsItemSelected(MenuItem item) {
  32. // Handle action bar item clicks here. The action bar will
  33. // automatically handle clicks on the Home/Up button, so long
  34. // as you specify a parent activity in AndroidManifest.xml.
  35. int id = item.getItemId();
  36. if (id == R.id.action_settings) {
  37. return true;
  38. }
  39. return super.onOptionsItemSelected(item);
  40. }
  41. /**
  42. * A placeholder fragment containing a simple view.
  43. */
  44. public static class PlaceholderFragment extends Fragment implements
  45. OnToggleStateChangedListener {
  46. private SlideButton slidebutton;
  47. public PlaceholderFragment() {
  48. }
  49. @Override
  50. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  51. Bundle savedInstanceState) {
  52. View rootView = inflater.inflate(R.layout.fragment_main, container,
  53. false);
  54. slidebutton = (SlideButton) rootView.findViewById(R.id.slidebutton1);
  55. // 设置一下开关的状态
  56. slidebutton.setToggleState(true); // 设置开关的状态为打开
  57. slidebutton.setmChangedListener(this);
  58. return rootView;
  59. }
  60. @Override
  61. public void onToggleStateChanged(boolean state) {
  62. // TODO Auto-generated method stub
  63. FragmentActivity activity = getActivity();
  64. if (state) {
  65. Toast.makeText(activity, "开关打开", 0).show();
  66. } else {
  67. Toast.makeText(activity, "开关关闭", 0).show();
  68. }
  69. }
  70. }
  71. }
package com.kince.slidebutton;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import android.os.Build; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} /**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment implements
OnToggleStateChangedListener { private SlideButton slidebutton; public PlaceholderFragment() {
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
slidebutton = (SlideButton) rootView.findViewById(R.id.slidebutton1);
// 设置一下开关的状态
slidebutton.setToggleState(true); // 设置开关的状态为打开
slidebutton.setmChangedListener(this);
return rootView;
} @Override
public void onToggleStateChanged(boolean state) {
// TODO Auto-generated method stub
FragmentActivity activity = getActivity();
if (state) {
Toast.makeText(activity, "开关打开", 0).show();
} else {
Toast.makeText(activity, "开关关闭", 0).show();
}
}
} }

未完待续。

滑动的Button的更多相关文章

  1. jQuery 效果 —— 滑动

    jQuery 效果 -- 滑动 1.向下滑动元素 (1)使用slideDown()方法可以用于向下滑动元素 $("button").click(function(){ $(&quo ...

  2. Android开发--仿微信语音对讲录音

    原文地址:http://www.2cto.com/kf/201502/378704.html 自微信出现以来取得了很好的成绩,语音对讲的实现更加方便了人与人之间的交流.今天来实践一下微信的语音对讲的录 ...

  3. [JS] JavaScript框架(1) jQuery

    jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用).events.实现动画效果,并且方便地为网站提供AJAX交互.jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应 ...

  4. 160914、ionic指令简单布局

    1) 添加引用类库(ionic样式和ionic js文件) 2) 标题栏,页脚栏,内容区 3) Js引入ionic类库,添加页面操作方法和对象 4) 数据初始化 5) Html页面绑定方法和对象 &l ...

  5. Android 实现用户列表信息的功能,然后选择删除幻灯片删除功能

    在项目开发过程中.经常须要对用户列表的信息进行删除的操作.Android中经常使用的删除操作方式有两种 .一种就是类似微信的滑动出现删除button方式,另一种是通过CheckBox进行选择.然后通过 ...

  6. Callback方法和JQuery链的解释

    这里讲到了一条语句运行多个JQuery方法(同一个元素)和动画100%完成后执行的callback方法. <!DOCTYPE html> <html> <head> ...

  7. 第三章 JQuery: HelloWorld--常见方法--css--选择器--筛选器--属性--效果--事件--数组操作--字符串操作--对象转换

    1.jQuery简介 为了简化JavaScript 的开发, 一些JavsScript 库诞生了. JavaScript库封装了很多预定义的对象和实用函数.能帮助使用者建立有高难度交互的页面, 并且兼 ...

  8. Ionic学习笔记3_ionic指令简单布局

    1)   添加引用类库(ionic样式和ionic js文件) 2)   标题栏,页脚栏,内容区 3)   Js引入ionic类库,添加页面操作方法和对象 4)   数据初始化 5)   Html页面 ...

  9. android 仿ios开关控件

    ios一些控件还是挺美丽的,可是对android程序猿来说可能比較苦逼,由于ios一些看起来简单的效果对android来说可能就没那么简单了,可是没办法非常多产品都是拿ios的一些控件叫android ...

随机推荐

  1. jQuery hide()并不等于hide(0)

    在实际使用中,经常用hide()函数来隐藏HTML元素,通常是没有什么问题的,但在一次做二级下拉菜单时遇到了问题,后来才发现有时候“speed”是不能省略的,即使“speed=0”,也就是说hide( ...

  2. Hive_初步见解,安装部署与测试

    一.hive是什么东东 1. 个人理解 hive就是一个基于hdfs运行于MapReduce上的一个java项目, 这个项目封装了jdbc,根据hdfs编写了处理数据库的DDL/DML,自带的 二进制 ...

  3. Hibernate调用存储过程和函数

    操作大批量数据或复杂逻辑,考虑到执行效率和代码量的时候,存储过程和函数在数据库中是预编译好的,调用执行效率高 // 调用过程 {call 过程名称(?,?,?)} public static void ...

  4. Scala命令设置JVM参数的规则

    Scala下设置JVM参数简单分析 Scala 启动shell脚本,简化后的scala REPL 启动命令大致如下所示: java -Xmx256M -Xms32M \-Xbootclasspath/ ...

  5. poj 2325 Persistent Numbers

    简单的贪心和高精度运算,主要还是要读懂题. #include"iostream" #include"stdio.h" #include"string& ...

  6. 【iCore3 双核心板】例程二十二:LAN_UDP实验——以太网数据传输

    实验指导书及代码包下载: http://pan.baidu.com/s/1kTPlJMJ iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  7. HTTP常见错误代码总结

    1.HTTP 401 用户验证失败.不允许继续访问 2.HTTP 403 禁止访问,访问web应用,没有指定要访问页面的名称 3.HTTP 404 请求的文件找不到,一般情况是在浏览器输入地址时,输入 ...

  8. jdk动态代理学习

    在jdk的好多底层代码中很多都使用jdk的动态代理,下面就写写简单的代码来look look. 老规矩先上代码: public interface SayDao { public String say ...

  9. mac 下面wireshark 找不到网卡

    终端上面,执行如下命令:   sudo chgrp admin /dev/bpf*   sudo chmod g+rw /dev/bpf* http://www.9upk.com/article/25 ...

  10. ERROR 2006 (HY000) at line xx: MySQL server has gone away 解决方法