Android怎么实现自定义开关按钮
导读:本文共8111.5字符,通常情况下阅读需要27分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 一、原理我们在界面的某一个区域里放置一个背景图A,这个图片一边为“开”,一边为“关”,在这个图片上放置一个图片B,图B大约为图A的一半,恰好可以覆盖掉图A上的“开”或者“关”,当我们手指点击图片的时候,图B在图A上滑动,相应的覆盖“开”或者“关”,这样就实现了开关按钮的效果。二、实现1、自定义View类MyToggle这个类继承自View类同时实现了OnTouc... ...
目录
(为您整理了一些要点),点击可以直达。一、原理
我们在界面的某一个区域里放置一个背景图A,这个图片一边为“开”,一边为“关”,在这个图片上放置一个图片B,图B大约为图A的一半,恰好可以覆盖掉图A上的“开”或者“关”,当我们手指点击图片的时候,图B在图A上滑动,相应的覆盖“开”或者“关”,这样就实现了开关按钮的效果。
二、实现
1、自定义View类MyToggle
这个类继承自View类同时实现了OnTouchListener接口,这个类实现的功能比较多,我们分解来看这个类。
1)属性字段
这个类中定义了不少的属性字段,每个属性字段的具体含义详见代码注释
具体实现代码如下:
//开关开启的背景图片privateBitmapbkgSwitchOn;//开关关闭的背景图片privateBitmapbkgSwitchOff;//开关的滚动图片privateBitmapbtnSlip;//当前开关是否为开启状态privatebooleantoggleStateOn;//开关状态的监听事件privateOnToggleStateListenertoggleStateListener;//记录开关·当前的状态privatebooleanisToggleStateListenerOn;//手指按下屏幕时的x坐标privatefloatproX;//手指滑动过程中当前x坐标privatefloatcurrentX;//是否处于滑动状态privatebooleanisSlipping;//记录上一次开关的状态privatebooleanproToggleState\=true;//开关开启时的矩形privateRectrect\_on;//开关关闭时的矩形privateRectrect\_off;
2)覆写View类的构造方法
我们在构造方法里完成的操作就是调用我们自己创建的init()方法
具体实现代码如下:
publicMyToggle(Contextcontext){super(context);init(context);}publicMyToggle(Contextcontext,AttributeSetattrs){super(context,attrs);init(context);}
3)创建init方法
这个方法中实现的操作就是设置触摸事件。
具体实现代码如下:
//初始化方法privatevoidinit(Contextcontext){setOnTouchListener(this);}
4)手指触摸事件回调方法onTouch
这个方法是当手指操作手机屏幕时,Android自动回调的方法,我们在这个方法中,监听手指的按下、移动和抬起事件,记录手指当前的X坐标来判断图片B的移动方向,从而实现图片B在图片A上的移动来达到按钮开和关的效果。
具体实现代码如下:
@OverridepublicbooleanonTouch(Viewv,MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION\_DOWN://记录手指按下时的x坐标proX\=event.getX();currentX\=proX;//将滑动标识设置为trueisSlipping\=true;break;caseMotionEvent.ACTION\_MOVE://记录手指滑动过程中当前x坐标currentX\=event.getX();break;caseMotionEvent.ACTION\_UP://手指抬起时将是否滑动的标识设置为falseisSlipping\=false;//处于关闭状态if(currentX<bkgSwitchOn.getWidth()/2){toggleStateOn\=false;}else{//处于开启状态toggleStateOn\=true;}//如果使用了开关监听器,同时开关的状态发生了改变,这时使用该代码if(isToggleStateListenerOn&&toggleStateOn!=proToggleState){proToggleState\=toggleStateOn;toggleStateListener.onToggleState(toggleStateOn);}break;}invalidate();//重绘returntrue;}
5)界面重绘方法onDraw
这个方法主要实现的是界面的重绘操作。
只要的思路是:
画背景图A:
当前手指滑动X坐标currentX大于图A宽度的一般时,按钮背景为开启状态;
当前手指滑动X坐标currentX小于图A宽度的一般时,按钮背景为关闭状态;
记录滑块B的X坐标:
B滑动时:
当前手指滑动X坐标currentX大于背景图A的宽度,则B坐标为图A宽度减去图B宽度
当前手指滑动X坐标currentX小于背景图A的宽度,则B坐标为当前X坐标currentX减去滑块宽度的一半
B静止:
当按钮处于“开”状态,则B坐标为“开”状态的最左边X坐标
当按钮处于“关”状态,则B坐标为“关”状态的最左边X坐标
具体实现代码如下:
@OverrideprotectedvoidonDraw(Canvascanvas){super.onDraw(canvas);//用来记录我们滑动块的位置intleft\_slip\=0;Matrixmatrix\=newMatrix();Paintpaint\=newPaint();if(currentX<bkgSwitchOn.getWidth()/2){//在画布上绘制出开关状态为关闭时的背景图片canvas.drawBitmap(bkgSwitchOff,matrix,paint);}else{//在画布上绘制出开关状态为开启时的背景图片canvas.drawBitmap(bkgSwitchOn,matrix,paint);}if(isSlipping){//开关是否处于滑动状态//滑动块是否超过了整个滑动按钮的宽度if(currentX\>bkgSwitchOn.getWidth()){//指定滑动块的位置left\_slip\=bkgSwitchOn.getWidth()\-btnSlip.getWidth();}else{//设置当前滑动块的位置left\_slip\=(int)(currentX\-btnSlip.getWidth()/2);}}else{//开关是否处于不滑动状态if(toggleStateOn){left\_slip\=rect\_on.left;}else{left\_slip\=rect\_off.left;}}if(left\_slip<0){left\_slip\=0;}elseif(left\_slip\>bkgSwitchOn.getWidth()\-btnSlip.getWidth()){left\_slip\=bkgSwitchOn.getWidth()\-btnSlip.getWidth();}//绘制图像canvas.drawBitmap(btnSlip,left\_slip,0,paint);}
6)计算开关的宽高
这里我通过覆写onMeasure来计算开关的宽度和高度
具体实现代码如下:
//计算开关的宽高@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){setMeasuredDimension(bkgSwitchOn.getWidth(),bkgSwitchOn.getHeight());}
7)设置图片资源信息
这个方法主要是供外界调用,向本类提供图片资源。
具体代码实现如下:
/\*\*\*设置图片资源信息\*@parambkgSwitch\_on\*@parambkgSwitch\_off\*@parambtn\_Slip\*/publicvoidsetImageRes(intbkgSwitch\_on,intbkgSwitch\_off,intbtn\_Slip){bkgSwitchOn\=BitmapFactory.decodeResource(getResources(),bkgSwitch\_on);bkgSwitchOff\=BitmapFactory.decodeResource(getResources(),bkgSwitch\_off);btnSlip\=BitmapFactory.decodeResource(getResources(),btn\_Slip);rect\_on\=newRect(bkgSwitchOn.getWidth()\-btnSlip.getWidth(),0,bkgSwitchOn.getWidth(),btnSlip.getHeight());rect\_off\=newRect(0,0,btnSlip.getWidth(),btnSlip.getHeight());}
8)设置开关按钮的状态
通过传递一个boolean类型的状态,我们在这个方法中将这个状态标识记录下来。
具体实现代码如下:
/\*\*\*设置开关按钮的状态\*@paramstate\*/publicvoidsetToggleState(booleanstate){toggleStateOn\=state;}
9)自定义开关状态监听器
我在这个类中定义了一个开关状态监听器接口OnToggleStateListener,里面有一个onToggleState方法来执行按钮的状态变化监听操作。
具体代码实现如下:
/\*\*\*自定义开关状态监听器\*@authorliuyazhuang\*\*/interfaceOnToggleStateListener{abstractvoidonToggleState(booleanstate);}
10)设置开关监听器
创建setOnToggleStateListener方法,传递一个OnToggleStateListener监听器对象,通过外界创建OnToggleStateListener对象,并将OnToggleStateListener对象传递进来,我们只需要将外界传递过来的OnToggleStateListener对象记录下来,同时当我们调用OnToggleStateListener接口中的onToggleState方法时,便实现了回调外界OnToggleStateListener实现类中的onToggleState方法。
具体代码实现如下:
//设置开关监听器并将是否设置了开关监听器设置为truepublicvoidsetOnToggleStateListener(OnToggleStateListenerlistener){toggleStateListener\=listener;isToggleStateListenerOn\=true;}
11)MyToggle完整代码如下:
packagecom.lyz.slip.toggle;importandroid.content.Context;importandroid.graphics.Bitmap;importandroid.graphics.BitmapFactory;importandroid.graphics.Canvas;importandroid.graphics.Matrix;importandroid.graphics.Paint;importandroid.graphics.Rect;importandroid.util.AttributeSet;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.View.OnTouchListener;/\*\*\*自定义开关类\*@authorliuyazhuang\*\*/publicclassMyToggleextendsViewimplementsOnTouchListener{//开关开启的背景图片privateBitmapbkgSwitchOn;//开关关闭的背景图片privateBitmapbkgSwitchOff;//开关的滚动图片privateBitmapbtnSlip;//当前开关是否为开启状态privatebooleantoggleStateOn;//开关状态的监听事件privateOnToggleStateListenertoggleStateListener;//记录开关·当前的状态privatebooleanisToggleStateListenerOn;//手指按下屏幕时的x坐标privatefloatproX;//手指滑动过程中当前x坐标privatefloatcurrentX;//是否处于滑动状态privatebooleanisSlipping;//记录上一次开关的状态privatebooleanproToggleState\=true;//开关开启时的矩形privateRectrect\_on;//开关关闭时的矩形privateRectrect\_off;publicMyToggle(Contextcontext){super(context);init(context);}publicMyToggle(Contextcontext,AttributeSetattrs){super(context,attrs);init(context);}//初始化方法privatevoidinit(Contextcontext){setOnTouchListener(this);}@OverridepublicbooleanonTouch(Viewv,MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION\_DOWN://记录手指按下时的x坐标proX\=event.getX();currentX\=proX;//将滑动标识设置为trueisSlipping\=true;break;caseMotionEvent.ACTION\_MOVE://记录手指滑动过程中当前x坐标currentX\=event.getX();break;caseMotionEvent.ACTION\_UP://手指抬起时将是否滑动的标识设置为falseisSlipping\=false;//处于关闭状态if(currentX<bkgSwitchOn.getWidth()/2){toggleStateOn\=false;}else{//处于开启状态toggleStateOn\=true;}//如果使用了开关监听器,同时开关的状态发生了改变,这时使用该代码if(isToggleStateListenerOn&&toggleStateOn!=proToggleState){proToggleState\=toggleStateOn;toggleStateListener.onToggleState(toggleStateOn);}break;}invalidate();//重绘returntrue;}@OverrideprotectedvoidonDraw(Canvascanvas){super.onDraw(canvas);//用来记录我们滑动块的位置intleft\_slip\=0;Matrixmatrix\=newMatrix();Paintpaint\=newPaint();if(currentX<bkgSwitchOn.getWidth()/2){//在画布上绘制出开关状态为关闭时的背景图片canvas.drawBitmap(bkgSwitchOff,matrix,paint);}else{//在画布上绘制出开关状态为开启时的背景图片canvas.drawBitmap(bkgSwitchOn,matrix,paint);}if(isSlipping){//开关是否处于滑动状态//滑动块是否超过了整个滑动按钮的宽度if(currentX\>bkgSwitchOn.getWidth()){//指定滑动块的位置left\_slip\=bkgSwitchOn.getWidth()\-btnSlip.getWidth();}else{//设置当前滑动块的位置left\_slip\=(int)(currentX\-btnSlip.getWidth()/2);}}else{//开关是否处于不滑动状态if(toggleStateOn){left\_slip\=rect\_on.left;}else{left\_slip\=rect\_off.left;}}if(left\_slip<0){left\_slip\=0;}elseif(left\_slip\>bkgSwitchOn.getWidth()\-btnSlip.getWidth()){left\_slip\=bkgSwitchOn.getWidth()\-btnSlip.getWidth();}//绘制图像canvas.drawBitmap(btnSlip,left\_slip,0,paint);}//计算开关的宽高@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){setMeasuredDimension(bkgSwitchOn.getWidth(),bkgSwitchOn.getHeight());}/\*\*\*设置图片资源信息\*@parambkgSwitch\_on\*@parambkgSwitch\_off\*@parambtn\_Slip\*/publicvoidsetImageRes(intbkgSwitch\_on,intbkgSwitch\_off,intbtn\_Slip){bkgSwitchOn\=BitmapFactory.decodeResource(getResources(),bkgSwitch\_on);bkgSwitchOff\=BitmapFactory.decodeResource(getResources(),bkgSwitch\_off);btnSlip\=BitmapFactory.decodeResource(getResources(),btn\_Slip);rect\_on\=newRect(bkgSwitchOn.getWidth()\-btnSlip.getWidth(),0,bkgSwitchOn.getWidth(),btnSlip.getHeight());rect\_off\=newRect(0,0,btnSlip.getWidth(),btnSlip.getHeight());}/\*\*\*设置开关按钮的状态\*@paramstate\*/publicvoidsetToggleState(booleanstate){toggleStateOn\=state;}/\*\*\*自定义开关状态监听器\*@authorliuyazhuang\*\*/interfaceOnToggleStateListener{abstractvoidonToggleState(booleanstate);}//设置开关监听器并将是否设置了开关监听器设置为truepublicvoidsetOnToggleStateListener(OnToggleStateListenerlistener){toggleStateListener\=listener;isToggleStateListenerOn\=true;}}
2、MainActivity
这个类实现很简单,主要的功能就是加载界面布局,初始化界面控件,调用MyToggle类中的方法实现按钮的开关效果
具体代码实现如下:
packagecom.lyz.slip.toggle;importandroid.app.Activity;importandroid.os.Bundle;importandroid.widget.Toast;importcom.lyz.slip.toggle.MyToggle.OnToggleStateListener;/\*\*\*程序主入口\*@authorliuyazhuang\*\*/publicclassMainActivityextendsActivity{//自定义开关对象privateMyToggletoggle;@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity\_main);toggle\=(MyToggle)findViewById(R.id.toggle);//设置开关显示所用的图片toggle.setImageRes(R.drawable.bkg\_switch,R.drawable.bkg\_switch,R.drawable.btn\_slip);//设置开关的默认状态true开启状态toggle.setToggleState(true);//设置开关的监听toggle.setOnToggleStateListener(newOnToggleStateListener(){@OverridepublicvoidonToggleState(booleanstate){//TODOAuto-generatedmethodstubif(state){Toast.makeText(getApplicationContext(),"开关开启",0).show();}else{Toast.makeText(getApplicationContext(),"开关关闭",0).show();}}});}}
3、布局文件activity_main.xml
这里我引用了自己定义的View类MyToggle。
具体代码实现如下:
<RelativeLayoutxmlns:android\="http://schemas.android.com/apk/res/android"xmlns:tools\="http://schemas.android.com/tools"android:layout\_width\="match\_parent"android:layout\_height\="match\_parent"\><com.lyz.slip.toggle.MyToggleandroid:id\="@+id/toggle"android:layout\_width\="wrap\_content"android:layout\_height\="wrap\_content"android:layout\_centerInParent\="true"/></RelativeLayout\>
4、AndroidManifest.xml
具体代码如下:
<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android\="http://schemas.android.com/apk/res/android"package\="com.lyz.slip.toggle"android:versionCode\="1"android:versionName\="1.0"\><uses-sdkandroid:minSdkVersion\="10"android:targetSdkVersion\="18"/><applicationandroid:allowBackup\="true"android:icon\="@drawable/ic\_launcher"android:label\="@string/app\_name"android:theme\="@style/AppTheme"\><activityandroid:name\="com.lyz.slip.toggle.MainActivity"android:label\="@string/app\_name"\><intent-filter\><actionandroid:name\="android.intent.action.MAIN"/><categoryandroid:name\="android.intent.category.LAUNCHER"/></intent-filter\></activity\></application\></manifest\>
三、运行效果
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Android怎么实现自定义开关按钮的详细内容,希望对您有所帮助,信息来源于网络。