广告
返回顶部
首页 > 资讯 > 精选 >Android怎么实现自定义开关按钮
  • 602
分享到

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

2023-06-30 11:06:04 602人浏览 泡泡鱼
摘要

这篇文章主要讲解了“Android怎么实现自定义开关按钮”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android怎么实现自定义开关按钮”吧!一、原理我们在界面的某一个区域里放置一个背景图

这篇文章主要讲解了“Android怎么实现自定义开关按钮”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android怎么实现自定义开关按钮”吧!

一、原理

我们在界面的某一个区域里放置一个背景图A,这个图片一边为“开”,一边为“关”,在这个图片上放置一个图片B,图B大约为图A的一半,恰好可以覆盖掉图A上的“开”或者“关”,当我们手指点击图片的时候,图B在图A上滑动,相应的覆盖“开”或者“关”,这样就实现了开关按钮的效果。

二、实现

1、自定义View类MyToggle

这个类继承自View类同时实现了OnTouchListener接口,这个类实现的功能比较多,我们分解来看这个类。

1)属性字段

这个类中定义了不少的属性字段,每个属性字段的具体含义详见代码注释

具体实现代码如下:

//开关开启的背景图片  private Bitmap bkgSwitchOn;  //开关关闭的背景图片  private Bitmap bkgSwitchOff;  //开关的滚动图片  private Bitmap btnSlip;  //当前开关是否为开启状态  private boolean toggleStateOn;  //开关状态的监听事件  private OnToggleStateListener toggleStateListener;  //记录开关·当前的状态  private boolean isToggleStateListenerOn;  //手指按下屏幕时的x坐标  private float proX;  //手指滑动过程中当前x坐标  private float currentX;  //是否处于滑动状态  private boolean isSlipping;  //记录上一次开关的状态  private boolean proToggleState \= true;  //开关开启时的矩形  private Rect rect\_on;  //开关关闭时的矩形  private Rect rect\_off;
2)覆写View类的构造方法

我们在构造方法里完成的操作就是调用我们自己创建的init()方法

具体实现代码如下:

public MyToggle(Context context) {    super(context);    init(context);  }    public MyToggle(Context context, AttributeSet attrs) {    super(context, attrs);    init(context);  }
3)创建init方法

这个方法中实现的操作就是设置触摸事件。

具体实现代码如下:

//初始化方法  private void init(Context context) {    setOnTouchListener(this);    }
4)手指触摸事件回调方法onTouch

这个方法是当手指操作手机屏幕时,Android自动回调的方法,我们在这个方法中,监听手指的按下、移动和抬起事件,记录手指当前的X坐标来判断图片B的移动方向,从而实现图片B在图片A上的移动来达到按钮开和关的效果。

具体实现代码如下:

@Override  public boolean onTouch(View v, MotionEvent event) {    switch (event.getAction()) {    case MotionEvent.ACTION\_DOWN:      //记录手指按下时的x坐标      proX \= event.getX();       currentX \= proX;      //将滑动标识设置为true      isSlipping \= true;      break;      case MotionEvent.ACTION\_MOVE:      //记录手指滑动过程中当前x坐标      currentX \= event.getX();      break;      case MotionEvent.ACTION\_UP:      //手指抬起时将是否滑动的标识设置为false      isSlipping \= false;      //处于关闭状态      if(currentX < bkgSwitchOn.getWidth() / 2 ){        toggleStateOn \= false;      } else { // 处于开启状态        toggleStateOn \= true;      }            // 如果使用了开关监听器,同时开关的状态发生了改变,这时使用该代码      if(isToggleStateListenerOn && toggleStateOn != proToggleState){        proToggleState \= toggleStateOn;        toggleStateListener.onToggleState(toggleStateOn);      }      break;    }    invalidate();//重绘    return true;  }
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坐标

具体实现代码如下:

@Override  protected void onDraw(canvas canvas) {    super.onDraw(canvas);    //用来记录我们滑动块的位置    int left\_slip \= 0;     Matrix matrix \= new Matrix();    Paint paint \= new Paint();    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;    } else if( left\_slip \> bkgSwitchOn.getWidth() \- btnSlip.getWidth()){      left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth();    }    //绘制图像    canvas.drawBitmap(btnSlip, left\_slip, 0, paint);  }
6)计算开关的宽高

这里我通过覆写onMeasure来计算开关的宽度和高度

具体实现代码如下:

//计算开关的宽高  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight());  }
7)设置图片资源信息

这个方法主要是供外界调用,向本类提供图片资源。

具体代码实现如下:

/\*\*   \* 设置图片资源信息   \* @param bkgSwitch\_on   \* @param bkgSwitch\_off   \* @param btn\_Slip   \*/  public void setImageRes(int bkgSwitch\_on, int bkgSwitch\_off, int btn\_Slip) {    bkgSwitchOn \= BitmapFactory.decodeResource(getResources(), bkgSwitch\_on);    bkgSwitchOff \= BitmapFactory.decodeResource(getResources(),bkgSwitch\_off);    btnSlip \= BitmapFactory.decodeResource(getResources(), btn\_Slip);    rect\_on \= new Rect(bkgSwitchOn.getWidth() \- btnSlip.getWidth(), 0,bkgSwitchOn.getWidth(), btnSlip.getHeight());    rect\_off \= new Rect(0, 0, btnSlip.getWidth(), btnSlip.getHeight());  }
8)设置开关按钮的状态

通过传递一个boolean类型的状态,我们在这个方法中将这个状态标识记录下来。

具体实现代码如下:

/\*\*   \* 设置开关按钮的状态   \* @param state   \*/  public void setToggleState(boolean state) {    toggleStateOn \= state;  }
9)自定义开关状态监听器

我在这个类中定义了一个开关状态监听器接口OnToggleStateListener,里面有一个onToggleState方法来执行按钮的状态变化监听操作。

具体代码实现如下:

/\*\*   \* 自定义开关状态监听器   \* @author liuyazhuang   \*   \*/  interface OnToggleStateListener {    abstract void onToggleState(boolean state);  }
10)设置开关监听器

创建setOnToggleStateListener方法,传递一个OnToggleStateListener监听器对象,通过外界创建OnToggleStateListener对象,并将OnToggleStateListener对象传递进来,我们只需要将外界传递过来的OnToggleStateListener对象记录下来,同时当我们调用OnToggleStateListener接口中的onToggleState方法时,便实现了回调外界OnToggleStateListener实现类中的onToggleState方法。

具体代码实现如下:

//设置开关监听器并将是否设置了开关监听器设置为true  public void setOnToggleStateListener(OnToggleStateListener listener) {    toggleStateListener \= listener;    isToggleStateListenerOn \= true;  }
11)MyToggle完整代码如下:
package com.lyz.slip.toggle;    import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.graphics.Canvas;  import android.graphics.Matrix;  import android.graphics.Paint;  import android.graphics.Rect;  import android.util.AttributeSet;  import android.view.MotionEvent;  import android.view.View;  import android.view.View.OnTouchListener;    /\*\*   \* 自定义开关类   \* @author liuyazhuang   \*   \*/  public class MyToggle extends View implements OnTouchListener {    //开关开启的背景图片    private Bitmap bkgSwitchOn;    //开关关闭的背景图片    private Bitmap bkgSwitchOff;    //开关的滚动图片    private Bitmap btnSlip;    //当前开关是否为开启状态    private boolean toggleStateOn;    //开关状态的监听事件    private OnToggleStateListener toggleStateListener;    //记录开关·当前的状态    private boolean isToggleStateListenerOn;    //手指按下屏幕时的x坐标    private float proX;    //手指滑动过程中当前x坐标    private float currentX;    //是否处于滑动状态    private boolean isSlipping;    //记录上一次开关的状态    private boolean proToggleState \= true;    //开关开启时的矩形    private Rect rect\_on;    //开关关闭时的矩形    private Rect rect\_off;      public MyToggle(Context context) {      super(context);      init(context);    }        public MyToggle(Context context, AttributeSet attrs) {      super(context, attrs);      init(context);    }        //初始化方法    private void init(Context context) {      setOnTouchListener(this);      }      @Override    public boolean onTouch(View v, MotionEvent event) {      switch (event.getAction()) {      case MotionEvent.ACTION\_DOWN:        //记录手指按下时的x坐标        proX \= event.getX();         currentX \= proX;        //将滑动标识设置为true        isSlipping \= true;        break;        case MotionEvent.ACTION\_MOVE:        //记录手指滑动过程中当前x坐标        currentX \= event.getX();        break;        case MotionEvent.ACTION\_UP:        //手指抬起时将是否滑动的标识设置为false        isSlipping \= false;        //处于关闭状态        if(currentX < bkgSwitchOn.getWidth() / 2 ){          toggleStateOn \= false;        } else { // 处于开启状态          toggleStateOn \= true;        }                // 如果使用了开关监听器,同时开关的状态发生了改变,这时使用该代码        if(isToggleStateListenerOn && toggleStateOn != proToggleState){          proToggleState \= toggleStateOn;          toggleStateListener.onToggleState(toggleStateOn);        }        break;      }            invalidate();//重绘      return true;    }      @Override    protected void onDraw(Canvas canvas) {      super.onDraw(canvas);      //用来记录我们滑动块的位置      int left\_slip \= 0;       Matrix matrix \= new Matrix();      Paint paint \= new Paint();      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;      } else if( left\_slip \> bkgSwitchOn.getWidth() \- btnSlip.getWidth()){        left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth();      }      //绘制图像      canvas.drawBitmap(btnSlip, left\_slip, 0, paint);    }    //计算开关的宽高    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight());    }        /\*\*     \* 设置图片资源信息     \* @param bkgSwitch\_on     \* @param bkgSwitch\_off     \* @param btn\_Slip     \*/    public void setImageRes(int bkgSwitch\_on, int bkgSwitch\_off, int btn\_Slip) {      bkgSwitchOn \= BitmapFactory.decodeResource(getResources(), bkgSwitch\_on);      bkgSwitchOff \= BitmapFactory.decodeResource(getResources(),bkgSwitch\_off);      btnSlip \= BitmapFactory.decodeResource(getResources(), btn\_Slip);      rect\_on \= new Rect(bkgSwitchOn.getWidth() \- btnSlip.getWidth(), 0,bkgSwitchOn.getWidth(), btnSlip.getHeight());      rect\_off \= new Rect(0, 0, btnSlip.getWidth(), btnSlip.getHeight());    }      /\*\*     \* 设置开关按钮的状态     \* @param state     \*/    public void setToggleState(boolean state) {      toggleStateOn \= state;    }      /\*\*     \* 自定义开关状态监听器     \* @author liuyazhuang     \*     \*/    interface OnToggleStateListener {      abstract void onToggleState(boolean state);    }    //设置开关监听器并将是否设置了开关监听器设置为true    public void setOnToggleStateListener(OnToggleStateListener listener) {      toggleStateListener \= listener;      isToggleStateListenerOn \= true;    }  }

2、MainActivity

这个类实现很简单,主要的功能就是加载界面布局,初始化界面控件,调用MyToggle类中的方法实现按钮的开关效果

具体代码实现如下:

package com.lyz.slip.toggle;    import android.app.Activity;  import android.os.Bundle;  import android.widget.Toast;    import com.lyz.slip.toggle.MyToggle.OnToggleStateListener;    /\*\*   \* 程序主入口   \* @author liuyazhuang   \*   \*/  public class MainActivity extends Activity {      //自定义开关对象      private MyToggle toggle;      @Override      public void onCreate(Bundle savedInstanceState) {          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(new OnToggleStateListener() {              @Override              public void onToggleState(boolean state) {                  // TODO Auto-generated method stub                  if(state){                      Toast.makeText(getApplicationContext(), "开关开启", 0).show();                  } else {                      Toast.makeText(getApplicationContext(), "开关关闭", 0).show();                  }              }          });      }  }

3、布局文件activity_main.xml

这里我引用了自己定义的View类MyToggle。

具体代码实现如下:

<RelativeLayout xmlns: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.MyToggle          android:id\="@+id/toggle"          android:layout\_width\="wrap\_content"          android:layout\_height\="wrap\_content"          android:layout\_centerInParent\="true"/>  </RelativeLayout\>

4、AndroidManifest.xml

具体代码如下:

<?xml version="1.0" encoding="utf-8"?>  <manifest xmlns:android\="http://schemas.android.com/apk/res/android"      package\="com.lyz.slip.toggle"      android:versionCode\="1"      android:versionName\="1.0" \>        <uses-sdk          android:minSdkVersion\="10"          android:targetSdkVersion\="18" />        <application          android:allowBackup\="true"          android:icon\="@drawable/ic\_launcher"          android:label\="@string/app\_name"          android:theme\="@style/AppTheme" \>          <activity              android:name\="com.lyz.slip.toggle.MainActivity"              android:label\="@string/app\_name" \>              <intent-filter\>                  <action android:name\="android.intent.action.MAIN" />                    <cateGory android:name\="android.intent.category.LAUNCHER" />              </intent-filter\>          </activity\>      </application\>  </manifest\>

三、运行效果

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

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

感谢各位的阅读,以上就是“Android怎么实现自定义开关按钮”的内容了,经过本文的学习后,相信大家对Android怎么实现自定义开关按钮这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Android怎么实现自定义开关按钮

本文链接: https://www.lsjlt.com/news/328486.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作