http://blog.csdn.net/wangjinyu501/article/details/27961303http://blog.csdn.net/wangjinyu501/article/details/27961303

http://blog.csdn.net/wangjinyu501/article/details/27961303

http://blog.csdn.net/wangjinyu501/article/details/27961303

http://blog.csdn.net/wangjinyu501/article/details/27961303

http://blog.csdn.net/wangjinyu501/article/details/27961303

http://blog.csdn.net/wangjinyu501/article/details/27961303



Android SwitchButton(滑动开关)

分类:Android 1420人阅读 评论(3) 收藏 举报 版本:1.0 日期:2014.5.172014.6.1 版权:© 2014 kince 转载注明出处
在介绍SwitchButton之前,先来看一下系统Button是如何实现的。源码如下: [html] view plain copy
  1. @RemoteView
  2. publicclassButtonextendsTextView{
  3. publicButton(Contextcontext){
  4. this(context,null);
  5. }
  6. publicButton(Contextcontext,AttributeSetattrs){
  7. this(context,attrs,com.android.internal.R.attr.buttonStyle);
  8. }
  9. publicButton(Contextcontext,AttributeSetattrs,intdefStyle){
  10. super(context,attrs,defStyle);
  11. }
  12. @Override
  13. publicvoidonInitializeAccessibilityEvent(AccessibilityEventevent){
  14. super.onInitializeAccessibilityEvent(event);
  15. event.setClassName(Button.class.getName());
  16. }
  17. @Override
  18. publicvoidonInitializeAccessibilityNodeInfo(AccessibilityNodeInfoinfo){
  19. super.onInitializeAccessibilityNodeInfo(info);
  20. info.setClassName(Button.class.getName());
  21. }
  22. }
是直接继承于TextView,所不同的是在构造方法中添加了Button的样式,并且在初始化可见性方面交由Button类自己来处理。虽然Button的实现比较简单,但是它的子类并不是这样。看一下:
直接子类只有有一个,CompoundButton。它是一个抽象类,而实现这个类的控件正是 CheckBox , RadioButton , Switch , ToggleButton 这四个,所以先重点说一下它。源码如下: [html] view plain copy
  1. /**
  2. *<p>
  3. *Abuttonwithtwostates,checkedandunchecked.Whenthebuttonispressed
  4. *orclicked,thestatechangesautomatically.
  5. *</p>
  6. *
  7. *<p><strong>XMLattributes</strong></p>
  8. *<p>
  9. *See{@linkandroid.R.styleable#CompoundButton
  10. *CompoundButtonAttributes},{@linkandroid.R.styleable#ButtonButton
  11. *Attributes},{@linkandroid.R.styleable#TextViewTextViewAttributes},{@link
  12. *android.R.styleable#ViewViewAttributes}
  13. *</p>
  14. */
  15. publicabstractclassCompoundButtonextendsButtonimplementsCheckable{
  16. privatebooleanmChecked;
  17. privateintmButtonResource;
  18. privatebooleanmBroadcasting;
  19. privateDrawablemButtonDrawable;
  20. privateOnCheckedChangeListenermOnCheckedChangeListener;
  21. privateOnCheckedChangeListenermOnCheckedChangeWidgetListener;
  22. privatestaticfinalint[]CHECKED_STATE_SET={
  23. R.attr.state_checked
  24. };
  25. publicCompoundButton(Contextcontext){
  26. this(context,null);
  27. }
  28. publicCompoundButton(Contextcontext,AttributeSetattrs){
  29. this(context,attrs,0);
  30. }
  31. publicCompoundButton(Contextcontext,AttributeSetattrs,intdefStyle){
  32. super(context,attrs,defStyle);
  33. TypedArraya=
  34. context.obtainStyledAttributes(
  35. attrs,com.android.internal.R.styleable.CompoundButton,defStyle,0);
  36. Drawabled=a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
  37. if(d!=null){
  38. setButtonDrawable(d);
  39. }
  40. booleanchecked=a
  41. .getBoolean(com.android.internal.R.styleable.CompoundButton_checked,false);
  42. setChecked(checked);
  43. a.recycle();
  44. }
  45. publicvoidtoggle(){
  46. setChecked(!mChecked);
  47. }
  48. @Override
  49. publicbooleanperformClick(){
  50. /*
  51. *XXX:Thesearetiny,needsomesurrounding'expandedtoucharea',
  52. *whichwillneedtobeimplementedinButtonifweonlyoverride
  53. *performClick()
  54. */
  55. /*Whenclicked,togglethestate*/
  56. toggle();
  57. returnsuper.performClick();
  58. }
  59. @ViewDebug.ExportedProperty
  60. publicbooleanisChecked(){
  61. returnmChecked;
  62. }
  63. /**
  64. *<p>Changesthecheckedstateofthisbutton.</p>
  65. *
  66. *@paramcheckedtruetocheckthebutton,falsetouncheckit
  67. */
  68. publicvoidsetChecked(booleanchecked){
  69. if(mChecked!=checked){
  70. mChecked=checked;
  71. refreshDrawableState();
  72. notifyViewAccessibilityStateChangedIfNeeded(
  73. AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
  74. //AvoidinfiniterecursionsifsetChecked()iscalledfromalistener
  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. *Registeracallbacktobeinvokedwhenthecheckedstateofthisbutton
  90. *changes.
  91. *
  92. *@paramlistenerthecallbacktocalloncheckedstatechange
  93. */
  94. publicvoidsetOnCheckedChangeListener(OnCheckedChangeListenerlistener){
  95. mOnCheckedChangeListener=listener;
  96. }
  97. /**
  98. *Registeracallbacktobeinvokedwhenthecheckedstateofthisbutton
  99. *changes.Thiscallbackisusedforinternalpurposeonly.
  100. *
  101. *@paramlistenerthecallbacktocalloncheckedstatechange
  102. *@hide
  103. */
  104. voidsetOnCheckedChangeWidgetListener(OnCheckedChangeListenerlistener){
  105. mOnCheckedChangeWidgetListener=listener;
  106. }
  107. /**
  108. *Interfacedefinitionforacallbacktobeinvokedwhenthecheckedstate
  109. *ofacompoundbuttonchanged.
  110. */
  111. publicstaticinterfaceOnCheckedChangeListener{
  112. /**
  113. *Calledwhenthecheckedstateofacompoundbuttonhaschanged.
  114. *
  115. *@parambuttonViewThecompoundbuttonviewwhosestatehaschanged.
  116. *@paramisCheckedThenewcheckedstateofbuttonView.
  117. */
  118. voidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked);
  119. }
  120. /**
  121. *SetthebackgroundtoagivenDrawable,identifiedbyitsresourceid.
  122. *
  123. *@paramresidtheresourceidofthedrawabletouseasthebackground
  124. */
  125. publicvoidsetButtonDrawable(intresid){
  126. if(resid!=0&&resid==mButtonResource){
  127. return;
  128. }
  129. mButtonResource=resid;
  130. Drawabled=null;
  131. if(mButtonResource!=0){
  132. d=getResources().getDrawable(mButtonResource);
  133. }
  134. setButtonDrawable(d);
  135. }
  136. /**
  137. *SetthebackgroundtoagivenDrawable
  138. *
  139. *@paramdTheDrawabletouseasthebackground
  140. */
  141. publicvoidsetButtonDrawable(Drawabled){
  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. publicvoidonInitializeAccessibilityEvent(AccessibilityEventevent){
  156. super.onInitializeAccessibilityEvent(event);
  157. event.setClassName(CompoundButton.class.getName());
  158. event.setChecked(mChecked);
  159. }
  160. @Override
  161. publicvoidonInitializeAccessibilityNodeInfo(AccessibilityNodeInfoinfo){
  162. super.onInitializeAccessibilityNodeInfo(info);
  163. info.setClassName(CompoundButton.class.getName());
  164. info.setCheckable(true);
  165. info.setChecked(mChecked);
  166. }
  167. @Override
  168. publicintgetCompoundPaddingLeft(){
  169. intpadding=super.getCompoundPaddingLeft();
  170. if(!isLayoutRtl()){
  171. finalDrawablebuttonDrawable=mButtonDrawable;
  172. if(buttonDrawable!=null){
  173. padding+=buttonDrawable.getIntrinsicWidth();
  174. }
  175. }
  176. returnpadding;
  177. }
  178. @Override
  179. publicintgetCompoundPaddingRight(){
  180. intpadding=super.getCompoundPaddingRight();
  181. if(isLayoutRtl()){
  182. finalDrawablebuttonDrawable=mButtonDrawable;
  183. if(buttonDrawable!=null){
  184. padding+=buttonDrawable.getIntrinsicWidth();
  185. }
  186. }
  187. returnpadding;
  188. }
  189. /**
  190. *@hide
  191. */
  192. @Override
  193. publicintgetHorizontalOffsetForDrawables(){
  194. finalDrawablebuttonDrawable=mButtonDrawable;
  195. return(buttonDrawable!=null)?buttonDrawable.getIntrinsicWidth():0;
  196. }
  197. @Override
  198. protectedvoidonDraw(Canvascanvas){
  199. super.onDraw(canvas);
  200. finalDrawablebuttonDrawable=mButtonDrawable;
  201. if(buttonDrawable!=null){
  202. finalintverticalGravity=getGravity()&Gravity.VERTICAL_GRAVITY_MASK;
  203. finalintdrawableHeight=buttonDrawable.getIntrinsicHeight();
  204. finalintdrawableWidth=buttonDrawable.getIntrinsicWidth();
  205. inttop=0;
  206. switch(verticalGravity){
  207. caseGravity.BOTTOM:
  208. top=getHeight()-drawableHeight;
  209. break;
  210. caseGravity.CENTER_VERTICAL:
  211. top=(getHeight()-drawableHeight)/2;
  212. break;
  213. }
  214. intbottom=top+drawableHeight;
  215. intleft=isLayoutRtl()?getWidth()-drawableWidth:0;
  216. intright=isLayoutRtl()?getWidth():drawableWidth;
  217. buttonDrawable.setBounds(left,top,right,bottom);
  218. buttonDrawable.draw(canvas);
  219. }
  220. }
  221. @Override
  222. protectedint[]onCreateDrawableState(intextraSpace){
  223. finalint[]drawableState=super.onCreateDrawableState(extraSpace+1);
  224. if(isChecked()){
  225. mergeDrawableStates(drawableState,CHECKED_STATE_SET);
  226. }
  227. returndrawableState;
  228. }
  229. @Override
  230. protectedvoiddrawableStateChanged(){
  231. super.drawableStateChanged();
  232. if(mButtonDrawable!=null){
  233. int[]myDrawableState=getDrawableState();
  234. //SetthestateoftheDrawable
  235. mButtonDrawable.setState(myDrawableState);
  236. invalidate();
  237. }
  238. }
  239. @Override
  240. protectedbooleanverifyDrawable(Drawablewho){
  241. returnsuper.verifyDrawable(who)||who==mButtonDrawable;
  242. }
  243. @Override
  244. publicvoidjumpDrawablesToCurrentState(){
  245. super.jumpDrawablesToCurrentState();
  246. if(mButtonDrawable!=null)mButtonDrawable.jumpToCurrentState();
  247. }
  248. staticclassSavedStateextendsBaseSavedState{
  249. booleanchecked;
  250. /**
  251. *Constructorcalledfrom{@linkCompoundButton#onSaveInstanceState()}
  252. */
  253. SavedState(ParcelablesuperState){
  254. super(superState);
  255. }
  256. /**
  257. *Constructorcalledfrom{@link#CREATOR}
  258. */
  259. privateSavedState(Parcelin){
  260. super(in);
  261. checked=(Boolean)in.readValue(null);
  262. }
  263. @Override
  264. publicvoidwriteToParcel(Parcelout,intflags){
  265. super.writeToParcel(out,flags);
  266. out.writeValue(checked);
  267. }
  268. @Override
  269. publicStringtoString(){
  270. return"CompoundButton.SavedState{"
  271. +Integer.toHexString(System.identityHashCode(this))
  272. +"checked="+checked+"}";
  273. }
  274. publicstaticfinalParcelable.Creator<SavedState>CREATOR
  275. =newParcelable.Creator<SavedState>(){
  276. publicSavedStatecreateFromParcel(Parcelin){
  277. returnnewSavedState(in);
  278. }
  279. publicSavedState[]newArray(intsize){
  280. returnnewSavedState[size];
  281. }
  282. };
  283. }
  284. @Override
  285. publicParcelableonSaveInstanceState(){
  286. //Forceourancestorclasstosaveitsstate
  287. setFreezesText(true);
  288. ParcelablesuperState=super.onSaveInstanceState();
  289. SavedStatess=newSavedState(superState);
  290. ss.checked=isChecked();
  291. returnss;
  292. }
  293. @Override
  294. publicvoidonRestoreInstanceState(Parcelablestate){
  295. SavedStatess=(SavedState)state;
  296. super.onRestoreInstanceState(ss.getSuperState());
  297. setChecked(ss.checked);
  298. requestLayout();
  299. }
  300. }
先从构造方法开始,在构造方法中, [html] view plain copy
  1. publicCompoundButton(Contextcontext,AttributeSetattrs,intdefStyle){
  2. super(context,attrs,defStyle);
  3. TypedArraya=
  4. context.obtainStyledAttributes(
  5. attrs,com.android.internal.R.styleable.CompoundButton,defStyle,0);
  6. Drawabled=a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
  7. if(d!=null){
  8. setButtonDrawable(d);
  9. }
  10. booleanchecked=a
  11. .getBoolean(com.android.internal.R.styleable.CompoundButton_checked,false);
  12. setChecked(checked);
  13. a.recycle();
  14. }
先是从attrs中读取定义的属性,一个是Drawable用于设置背景;一个是布尔类型变量用于判断是否check过。设置背景使用的是setButtonDrawable()方法,代码如下: [html] view plain copy
  1. /**
  2. *SetthebackgroundtoagivenDrawable
  3. *
  4. *@paramdTheDrawabletouseasthebackground
  5. */
  6. publicvoidsetButtonDrawable(Drawabled){
  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. }
这个方法写的就比较完善,可以作为一个学习的典范。首先判断传递过来的Drawable是否为空,如果不为空并且默认的Drawable也不为空,那么取消默认Drawable的callback,然后调用 unscheduleDrawable 方法。这个方法代码如下: [html] view plain copy
  1. /**
  2. *UnscheduleanyeventsassociatedwiththegivenDrawable.Thiscanbe
  3. *usedwhenselectinganewDrawableintoaview,sothattheprevious
  4. *oneiscompletelyunscheduled.
  5. *
  6. *@paramwhoTheDrawabletounschedule.
  7. *
  8. *@see#drawableStateChanged
  9. */
  10. publicvoidunscheduleDrawable(Drawablewho){
  11. if(mAttachInfo!=null&&who!=null){
  12. mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
  13. Choreographer.CALLBACK_ANIMATION,null,who);
  14. }
  15. }
从方法注释中可以看出它的用途,正是更换Drawable时候使用的。接下来开始重新设置Drawable,包括回调、可见性、最小高度。最后调用 refreshDrawableState() 方法,这个是View类的方法,用于更新Drawable状态。 然后再回过头看一下 setChecked (checked)方法,这个用于设置check,也就是button的点击状态。代码如下: [html] view plain copy
  1. /**
  2. *<p>Changesthecheckedstateofthisbutton.</p>
  3. *
  4. *@paramcheckedtruetocheckthebutton,falsetouncheckit
  5. */
  6. publicvoidsetChecked(booleanchecked){
  7. if(mChecked!=checked){
  8. mChecked=checked;
  9. refreshDrawableState();
  10. notifyViewAccessibilityStateChangedIfNeeded(
  11. AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
  12. //AvoidinfiniterecursionsifsetChecked()iscalledfromalistener
  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. }
在这个方法中多出了一个接口,这个接口真是check的一个回调接口,代码如下: [html] view plain copy
  1. /**
  2. *Interfacedefinitionforacallbacktobeinvokedwhenthecheckedstate
  3. *ofacompoundbuttonchanged.
  4. */
  5. publicstaticinterfaceOnCheckedChangeListener{
  6. /**
  7. *Calledwhenthecheckedstateofacompoundbuttonhaschanged.
  8. *
  9. *@parambuttonViewThecompoundbuttonviewwhosestatehaschanged.
  10. *@paramisCheckedThenewcheckedstateofbuttonView.
  11. */
  12. voidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked);
  13. }
这种回调接口在Android中处处可见,之前的文章也有介绍过。但是在上面的方法,它使用了一个mBroadcasting变量,进而巧妙地避免了重复递归的问题,大家自己感受一下。 然后就是ondraw()方法了,把之前的drawable画出来。代码如下: [html] view plain copy
  1. @Override
  2. protectedvoidonDraw(Canvascanvas){
  3. super.onDraw(canvas);
  4. finalDrawablebuttonDrawable=mButtonDrawable;
  5. if(buttonDrawable!=null){
  6. finalintverticalGravity=getGravity()&Gravity.VERTICAL_GRAVITY_MASK;
  7. finalintdrawableHeight=buttonDrawable.getIntrinsicHeight();
  8. finalintdrawableWidth=buttonDrawable.getIntrinsicWidth();
  9. inttop=0;
  10. switch(verticalGravity){
  11. caseGravity.BOTTOM:
  12. top=getHeight()-drawableHeight;
  13. break;
  14. caseGravity.CENTER_VERTICAL:
  15. top=(getHeight()-drawableHeight)/2;
  16. break;
  17. }
  18. intbottom=top+drawableHeight;
  19. intleft=isLayoutRtl()?getWidth()-drawableWidth:0;
  20. intright=isLayoutRtl()?getWidth():drawableWidth;
  21. buttonDrawable.setBounds(left,top,right,bottom);
  22. buttonDrawable.draw(canvas);
  23. }
  24. }
看得出来,在onDrawable()方法中,最主要的部分还是如何确定上下左右四个参数。确定完后就可以画出来了。但是,CompoundButton是一个抽象类,并不能直接使用,那看一下它的子类是如何实现的:
1、CheckBox [html] view plain copy
  1. publicclassCheckBoxextendsCompoundButton{
  2. publicCheckBox(Contextcontext){
  3. this(context,null);
  4. }
  5. publicCheckBox(Contextcontext,AttributeSetattrs){
  6. this(context,attrs,com.android.internal.R.attr.checkboxStyle);
  7. }
  8. publicCheckBox(Contextcontext,AttributeSetattrs,intdefStyle){
  9. super(context,attrs,defStyle);
  10. }
  11. @Override
  12. publicvoidonInitializeAccessibilityEvent(AccessibilityEventevent){
  13. super.onInitializeAccessibilityEvent(event);
  14. event.setClassName(CheckBox.class.getName());
  15. }
  16. @Override
  17. publicvoidonInitializeAccessibilityNodeInfo(AccessibilityNodeInfoinfo){
  18. super.onInitializeAccessibilityNodeInfo(info);
  19. info.setClassName(CheckBox.class.getName());
  20. }
  21. }
和Button的实现差不多,使用了一个自己的样式。并且也是重写了那两个方法。再来看一下RadioButton, [html] view plain copy
  1. publicclassRadioButtonextendsCompoundButton{
  2. publicRadioButton(Contextcontext){
  3. this(context,null);
  4. }
  5. publicRadioButton(Contextcontext,AttributeSetattrs){
  6. this(context,attrs,com.android.internal.R.attr.radioButtonStyle);
  7. }
  8. publicRadioButton(Contextcontext,AttributeSetattrs,intdefStyle){
  9. super(context,attrs,defStyle);
  10. }
  11. /**
  12. *{@inheritDoc}
  13. *<p>
  14. *Iftheradiobuttonisalreadychecked,thismethodwillnottoggletheradiobutton.
  15. */
  16. @Override
  17. publicvoidtoggle(){
  18. //weoverridetopreventtogglewhentheradioisalready
  19. //checked(asopposedtocheckboxeswidgets)
  20. if(!isChecked()){
  21. super.toggle();
  22. }
  23. }
  24. @Override
  25. publicvoidonInitializeAccessibilityEvent(AccessibilityEventevent){
  26. super.onInitializeAccessibilityEvent(event);
  27. event.setClassName(RadioButton.class.getName());
  28. }
  29. @Override
  30. publicvoidonInitializeAccessibilityNodeInfo(AccessibilityNodeInfoinfo){
  31. super.onInitializeAccessibilityNodeInfo(info);
  32. info.setClassName(RadioButton.class.getName());
  33. }
  34. }
和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()方法,动态画出按钮。 代码如下: [html] view plain copy
  1. /**
  2. *
  3. */
  4. packagecom.kince.slidebutton;
  5. importandroid.content.Context;
  6. importandroid.graphics.Bitmap;
  7. importandroid.graphics.BitmapFactory;
  8. importandroid.graphics.Canvas;
  9. importandroid.util.AttributeSet;
  10. importandroid.util.Log;
  11. importandroid.view.MotionEvent;
  12. importandroid.view.View;
  13. /**
  14. *@authorkince
  15. *@category左右手势滑动button
  16. *@serial1.0.0
  17. *@since2014.5.17
  18. *@seehttp://blog.csdn.net/wangjinyu501
  19. *
  20. */
  21. publicclassSlideButtonextendsView{
  22. privateBitmapslideBitMap;//滑动图片
  23. privateBitmapswitchBitMap;//背景图片
  24. privateintslideBitMapWidth;//滑动图片宽度
  25. privateintswitchBitMapWidth;//背景图片宽度
  26. privateintswitchBitMapHeight;//背景图片高度
  27. privatebooleancurrentState;//开关状态
  28. privatebooleanisSliding=false;//是否正在滑动中
  29. privateintcurrentX;//当前开关的位置
  30. privateOnToggleStateChangedListenermChangedListener;//回调接口
  31. /**
  32. *@paramcontext
  33. *在java代码中直接调用使用此构造方法
  34. */
  35. publicSlideButton(Contextcontext){
  36. this(context,null);
  37. //TODOAuto-generatedconstructorstub
  38. }
  39. /**
  40. *@paramcontext
  41. *@paramattrs
  42. *在xml中使用要用到这个方法
  43. */
  44. publicSlideButton(Contextcontext,AttributeSetattrs){
  45. this(context,attrs,0);
  46. //TODOAuto-generatedconstructorstub
  47. }
  48. /**
  49. *@paramcontext
  50. *@paramattrs
  51. *@paramdefStyleAttr
  52. *指定一个样式
  53. */
  54. publicSlideButton(Contextcontext,AttributeSetattrs,intdefStyleAttr){
  55. super(context,attrs,defStyleAttr);
  56. initBitmap();
  57. }
  58. /**
  59. *@category加载背景图片以及开关图片然后获取各自的宽高
  60. *
  61. */
  62. privatevoidinitBitmap(){
  63. //TODOAuto-generatedmethodstub
  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. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
  75. //TODOAuto-generatedmethodstub
  76. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
  77. setMeasuredDimension(switchBitMapWidth,switchBitMapHeight);//设置控件的宽高
  78. }
  79. @Override
  80. protectedvoidonDraw(Canvascanvas){
  81. //绘制button背景图片
  82. canvas.drawBitmap(switchBitMap,0,0,null);
  83. //绘制滑动开关
  84. if(isSliding){//如果当前状态是滑动中则动态绘制开关
  85. intdis=currentX-slideBitMapWidth/2;
  86. if(dis<0){
  87. dis=0;
  88. }elseif(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. publicbooleanonTouchEvent(MotionEventevent){
  104. //手势识别判断滑动方向
  105. intaction=event.getAction();
  106. switch(action){
  107. caseMotionEvent.ACTION_DOWN:
  108. isSliding=true;
  109. currentX=(int)event.getX();
  110. break;
  111. caseMotionEvent.ACTION_MOVE:
  112. currentX=(int)event.getX();
  113. Log.i("currentX",currentX+"");
  114. break;
  115. caseMotionEvent.ACTION_UP:
  116. isSliding=false;
  117. intbgCenter=switchBitMapWidth/2;
  118. booleanstate=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. returntrue;
  129. }
  130. publicOnToggleStateChangedListenergetmChangedListener(){
  131. returnmChangedListener;
  132. }
  133. publicvoidsetmChangedListener(
  134. OnToggleStateChangedListenermChangedListener){
  135. this.mChangedListener=mChangedListener;
  136. }
  137. publicbooleanisToggleState(){
  138. returncurrentState;
  139. }
  140. publicvoidsetToggleState(booleancurrentState){
  141. this.currentState=currentState;
  142. }
  143. }
回调接口, [html] view plain copy
  1. packagecom.kince.slidebutton;
  2. **
  3. *@authorkince
  4. *
  5. */
  6. ublicinterfaceOnToggleStateChangedListener{
  7. /**
  8. *@category
  9. *@paramstate
  10. */
  11. publicvoidonToggleStateChanged(booleanstate);
Activity代码, [html] view plain copy
  1. packagecom.kince.slidebutton;
  2. importandroid.support.v7.app.ActionBarActivity;
  3. importandroid.support.v7.app.ActionBar;
  4. importandroid.support.v4.app.Fragment;
  5. importandroid.support.v4.app.FragmentActivity;
  6. importandroid.os.Bundle;
  7. importandroid.view.LayoutInflater;
  8. importandroid.view.Menu;
  9. importandroid.view.MenuItem;
  10. importandroid.view.View;
  11. importandroid.view.ViewGroup;
  12. importandroid.widget.Toast;
  13. importandroid.os.Build;
  14. publicclassMainActivityextendsActionBarActivity{
  15. @Override
  16. protectedvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.activity_main);
  19. if(savedInstanceState==null){
  20. getSupportFragmentManager().beginTransaction()
  21. .add(R.id.container,newPlaceholderFragment()).commit();
  22. }
  23. }
  24. @Override
  25. publicbooleanonCreateOptionsMenu(Menumenu){
  26. //Inflatethemenu;thisaddsitemstotheactionbarifitispresent.
  27. getMenuInflater().inflate(R.menu.main,menu);
  28. returntrue;
  29. }
  30. @Override
  31. publicbooleanonOptionsItemSelected(MenuItemitem){
  32. //Handleactionbaritemclickshere.Theactionbarwill
  33. //automaticallyhandleclicksontheHome/Upbutton,solong
  34. //asyouspecifyaparentactivityinAndroidManifest.xml.
  35. intid=item.getItemId();
  36. if(id==R.id.action_settings){
  37. returntrue;
  38. }
  39. returnsuper.onOptionsItemSelected(item);
  40. }
  41. /**
  42. *Aplaceholderfragmentcontainingasimpleview.
  43. */
  44. publicstaticclassPlaceholderFragmentextendsFragmentimplements
  45. OnToggleStateChangedListener{
  46. privateSlideButtonslidebutton;
  47. publicPlaceholderFragment(){
  48. }
  49. @Override
  50. publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
  51. BundlesavedInstanceState){
  52. ViewrootView=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. returnrootView;
  59. }
  60. @Override
  61. publicvoidonToggleStateChanged(booleanstate){
  62. //TODOAuto-generatedmethodstub
  63. FragmentActivityactivity=getActivity();
  64. if(state){
  65. Toast.makeText(activity,"开关打开",0).show();
  66. }else{
  67. Toast.makeText(activity,"开关关闭",0).show();
  68. }
  69. }
  70. }
  71. }
未完待续。













更多相关文章

  1. ViewFlipper
  2. Android(安卓)各种音量的获取和设置
  3. Android学习笔记----Android简单有效的闪屏制作
  4. android 获取IP
  5. Android(安卓)onSaveInstanceState和onRestoreInstanceState触发
  6. Android(安卓)判断 app 是否安装的方法 (native.js)
  7. android EditText 只能输入无法删除的解决方法
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. TransactionSystemException:无法提交JPA
  2. java实现约瑟夫问题
  3. Java:在特定队列大小之后,以提交方式阻塞
  4. 帮忙解析一下 java解析普通的文本文件,提
  5. javax.mail.AuthenticationFailedExcepti
  6. 一个非常不错的纯源码“PDF转换swf”完全
  7. 第二届战神杯线上编程挑战赛月赛第二题:数
  8. 如何从java获取spring配置文件名称
  9. Java多线程wait和notify协作,按序打印abc
  10. Java 网络编程(一) 网络基础知识