Android怎么实现自定义开关按钮(android,开发技术)

时间:2024-05-03 12:11:43 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

一、原理

我们在界面的某一个区域里放置一个背景图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\>

三、运行效果

Android怎么实现自定义开关按钮

Android怎么实现自定义开关按钮

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Android怎么实现自定义开关按钮的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:OpenCV中的颜色空间实例分析下一篇:

23 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18