参考文档:

http://blog.csdn.net/singwhatiwanna/article/details/9254309

Android开发文档API的View

本文中自定义开关MySwitch是我在阅读了上述文档,根据自己的理解写的,所引用的图片资源来自http://home.ustc.edu.cn/~voa/res/HelloJni.apk

代码已在Android 2.2的模拟器和Android 4.2.1的手机上测试,均可运行。

手机测试效果如下:

a 默认效果

b 向右滑,滑过中间位置动效果

c 松开手指,自动滑到右部效果

d向左滑,滑过中间位置动效果

松开手指,又回到a所示状态。

MySwitch代码:

packagecn.mswitch;importandroid.content.Context;importandroid.content.res.Resources;importandroid.graphics.Bitmap;importandroid.graphics.BitmapFactory;importandroid.graphics.Canvas;importandroid.graphics.Paint;importandroid.graphics.Rect;importandroid.util.AttributeSet;importandroid.util.Log;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.ViewGroup.LayoutParams;/***自定义开关按钮类,打开状态值为true,关闭为false*@authorliuwh*@since2014-05-2*/publicclassMySwitchextendsView{privatestaticfinalStringTAG="MySwitch";/***关闭状态*/privatestaticfinalintSTATE_OFF=0;/***打开状态*/privatestaticfinalintSTATE_ON=1;/***正在滑动状态*/privatestaticfinalintSTATE_SCROLL=2;privatestaticBitmapbitmapOFF;//关闭状态背景图片privatestaticBitmapbitmapON;//打开状态背景图片privatestaticBitmapbitmapThumb;//圆点图片(为正方形)privatestaticintbgWidth;//背景宽度privatestaticintbgHeigth;//背景高度privatestaticintthumbWidth;//圆点宽度/***MySwitch状态标志,值为true或false,默认为false,即关闭*/privatebooleanmState=false;/***滑动事件标志,true为滑动事件,false则为点击事件*/privatebooleanmHasScroll=false;/***MySwitch当前状态标志,值为0,1,2,*0对应状态STATE_OFF*1对应状态STATE_ON*2对应状态STATE_SCROLL*/privateintcurrState=0;publicMySwitch(Contextcontext){super(context);//DisplayMetricsdm=newDisplayMetrics();//floatdensity=context.getResources().getDisplayMetrics().density;//Log.i(TAG,"density="+density);//屏幕密度}publicMySwitch(Contextcontext,AttributeSetats){super(context,ats);init();}publicMySwitch(Contextcontext,AttributeSetats,intdfStyle){super(context,ats,dfStyle);init();}/***初始化图片对象,宽高数据和当前状态*/privatevoidinit(){Resourcesres=getResources();bitmapThumb=BitmapFactory.decodeResource(res,R.drawable.switch_thumb);bitmapON=BitmapFactory.decodeResource(res,R.drawable.bg_switch_on);bitmapOFF=BitmapFactory.decodeResource(res,R.drawable.bg_switch_off);bgWidth=bitmapON.getWidth();bgHeigth=bitmapON.getHeight();thumbWidth=bitmapThumb.getWidth();currState=mState?STATE_ON:STATE_OFF;Log.i(TAG,"bw:"+bgWidth+",bh:"+bgHeigth+",tw:"+thumbWidth);}@OverridepublicvoidsetLayoutParams(LayoutParamsparams){//设置MySwitch的View区域宽高params.width=bgWidth;params.height=bgHeigth;super.setLayoutParams(params);}/***获取MySwitch对象的状态*@returnboolean值*/publicbooleangetMState(){returnthis.mState;}/***设置MySwitch对象的状态*@paramisOnboolean值*/publicvoidsetMState(booleanmState){if(this.mState!=mState){//更改当前状态currState的值currState=mState?STATE_ON:STATE_OFF;//通知重新画图MySwitch.this.postInvalidate();}this.mState=mState;}//状态改变监听接口对象privateOnMySwicthStateChangedListenermsl;/***设置状态改变监听*@parammslOnMySwicthStateChangedListener对象*/publicvoidsetOnMySwicthStateChangedListener(OnMySwicthStateChangedListenermsl){this.msl=msl;}privateintstartX;privateintcurrX=0;@OverridepublicbooleanonTouchEvent(MotionEventevent){intpointers=event.getPointerCount();//如果不是一个手指,则不做处理if(pointers>1)returntrue;intaction=event.getAction();switch(action){caseMotionEvent.ACTION_DOWN://手指按下startX=(int)event.getX();//Log.i(TAG,"start:"+startX);break;caseMotionEvent.ACTION_MOVE://手指滑动//设置滑动标志为true,并将当前状态置为滑动mHasScroll=true;currState=STATE_SCROLL;currX=(int)event.getX();currX=currX>bgWidth?bgWidth:currX;//通知重画MySwitch的View区域this.invalidate();//Log.i(TAG,"currx:"+currX);break;caseMotionEvent.ACTION_UP://手指松开intendX=(int)event.getX();//Log.i(TAG,"endX:"+endX);intmidX=bgWidth/2;//Log.i(TAG,"midX="+midX);MyAnimationTransmat=null;if(mHasScroll){//滑动事件Log.i(TAG,"scrollevent");//已滑到0或bgWidth位置,判断是否需要发送状态改变通知,不再重画MySwitch区域图像if(endX>=bgWidth||endX<=0){isChange=startX>midX?endX<=0:endX>=bgWidth;mState=isChange?endX>=bgWidth:mState;postStateChanged();mHasScroll=false;returntrue;}//图片滑向的终点位置inttoX=endX<midX?0:bgWidth;mat=newMyAnimationTrans(endX,toX);}else{//点击事件Log.i(TAG,"clickevent");if(mState){//点击处在关闭区域,滑向0位置if(endX<midX){mat=newMyAnimationTrans(endX,0);}}else{//点击处在打开区域,滑向bgWidth位置if(endX>midX){mat=newMyAnimationTrans(endX,bgWidth);}}}//处理状态改变响应事件isChange=mState?endX<midX:endX>midX;mState=isChange?endX>midX:mState;postStateChanged();//将滑动标志更改为falsemHasScroll=false;if(mat!=null){this.invalidate();newThread(mat).start();}break;default:break;}returntrue;}//状态是否发生改变,true为发生改变,false为无privatebooleanisChange=false;/***响应状态改变监听事件*/privatevoidpostStateChanged(){//通知状态改变监听接口if(isChange&&msl!=null){msl.onMySwicthChanged(this);isChange=false;Log.i(TAG,"ACTION_UP,发送状态改变事件,将isChange置为false!");}}@OverrideprotectedvoidonDraw(Canvascanvas){super.onDraw(canvas);//关闭状态if(currState==STATE_OFF){drawBitmap(canvas,null,null,bitmapOFF);drawBitmap(canvas,null,null,bitmapThumb);}//打开状态elseif(currState==STATE_ON){drawBitmap(canvas,null,null,bitmapON);intcount=canvas.getSaveCount();canvas.translate(bgWidth-thumbWidth,0);drawBitmap(canvas,null,null,bitmapThumb);canvas.restoreToCount(count);}//滑动状态else{intcount=canvas.save();if(currX>bgWidth/2){drawBitmap(canvas,null,null,bitmapON);Log.i(TAG,"状态改变为打开,mState="+mState);}else{drawBitmap(canvas,null,null,bitmapOFF);Log.i(TAG,"状态改变为关闭,mState="+mState);}canvas.restoreToCount(count);count=canvas.save();inttoX=currX-thumbWidth/2;toX=toX<0?0:toX>(bgWidth-thumbWidth)?(bgWidth-thumbWidth):toX;//Log.i(TAG,"toX="+toX);canvas.translate(toX,0);drawBitmap(canvas,null,null,bitmapThumb);canvas.restoreToCount(count);}}/***将图片画到屏幕中*@paramcanvasCanvas对象*@paramfromRC初始位置*@paramdestRC终点位置*@parambitmap图片对象*/privatevoiddrawBitmap(Canvascanvas,RectfromRC,RectdestRC,Bitmapbitmap){//destRC为null,则从(0,0)位置开始画图destRC=destRC==null?newRect(0,0,bitmap.getWidth(),bitmap.getHeight()):destRC;Paintpaint=newPaint();canvas.drawBitmap(bitmap,fromRC,destRC,paint);}/***自定义动画类*@authorliuwh**/privateclassMyAnimationTransimplementsRunnable{privateintfromX;privateintendX;privatestaticfinalintSPEED=5;//默认移动速度publicMyAnimationTrans(finalintfromX,finalintendX){this.fromX=fromX;this.endX=endX;}@Overridepublicvoidrun(){intspeed=endX>fromX?SPEED:-SPEED;currX=endX;//是否结束循环标志,true为结束booleanisEnd=false;while(true){currX+=speed;if(currX>bgWidth||currX<0){currX=speed>0?bgWidth:0;isEnd=true;//结束循环}MySwitch.this.currState=STATE_SCROLL;MySwitch.this.postInvalidate();if(isEnd){break;}try{Thread.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}}}}/***状态改变监听*@authorliuwh**/publicinterfaceOnMySwicthStateChangedListener{voidonMySwicthChanged(MySwitchmySwitch);}}



更多相关文章

  1. Android中用onSaveInstanceState保存Fragment状态的方法
  2. android之WIFI网络操作笔记
  3. android 下载图片到本地 sdcard
  4. android仿苹果弹性布局
  5. Android手机亮屏流程分析
  6. android 显示电池电量
  7. TelephonyManager类:Android手机及Sim卡状态的获取
  8. Android(安卓)CoordinatorLayout高级用法之自定义Behavior
  9. Android(安卓)CoordinatorLayout自定义Behavior实现依赖滚动布局

随机推荐

  1. new delete
  2. 51单片机最小系统电路-设计教程
  3. 在苹果Mac上的“邮件”中如何使用列布局?
  4. 做支付需要了解哪些行业知识?
  5. 升级API网关Kong
  6. Google Guice之AOP
  7. 为什么有些BI工具做数据可视化项目频频失
  8. 干货 | 超声波及其传感器工作原理
  9. Kibana 之 安装部署
  10. Kafka性能篇:为什么Kafka这么快?