自定义开关
16lz
2021-01-26
参考文档:
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);}}
更多相关文章
- Android中用onSaveInstanceState保存Fragment状态的方法
- android之WIFI网络操作笔记
- android 下载图片到本地 sdcard
- android仿苹果弹性布局
- Android手机亮屏流程分析
- android 显示电池电量
- TelephonyManager类:Android手机及Sim卡状态的获取
- Android(安卓)CoordinatorLayout高级用法之自定义Behavior
- Android(安卓)CoordinatorLayout自定义Behavior实现依赖滚动布局