自定义Android 开关MyToggle,滑动开启自己需要的功能

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.os.Handler;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by ling on 2017/12/5.
 */

public class MyToggle extends View implements View.OnTouchListener {

  private final String TAG = MyToggle.class.getSimpleName();
  //开关开启的背景图片
  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;

  float lineStart; //直线段开始的位置(横坐标,即
  float lineEnd; //直线段结束的位置(纵坐标
  private boolean currentState;
  private int left_slip = 0;

  private float bkgSwitchOnWidth;
  private float btnSlipWidth;

  public MyToggle(Context context) {
    super(context);
    this.setOnTouchListener(this);
    init(getContext());
  }

  public MyToggle(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(getContext());
  }

  public MyToggle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(getContext());
  }

  //初始化方法
  private void init(Context context) {
    setOnTouchListener(this);
  }

  @Override
  public boolean onTouch(View view, MotionEvent motionEvent) {
    switch (motionEvent.getAction()) {
      case MotionEvent.ACTION_DOWN:
        //记录手指按下时的x坐标
        proX = motionEvent.getX();
        currentX = proX;
        //将滑动标识设置为true
        isSlipping = true;
        break;

      case MotionEvent.ACTION_MOVE:
        //记录手指滑动过程中当前x坐标
        currentX = motionEvent.getX();
        isSlipping = true;
        break;

      case MotionEvent.ACTION_UP:
        //手指抬起时将是否滑动的标识设置为false
        isSlipping = false;
        //处于关闭状态
        if (currentX < bkgSwitchOn.getWidth() / 2) {
          toggleStateOn = false;
        } else { // 处于开启状态
          toggleStateOn = true;
          //do  something
        }
        handler.sendEmptyMessageDelayed(0, 10);
        // 如果使用了开关监听器,同时开关的状态发生了改变,这时使用该代码
//                if(isToggleStateListenerOn && toggleStateOn != proToggleState){
        if (isToggleStateListenerOn && toggleStateOn) {
//                    proToggleState = toggleStateOn;
          toggleStateListener.onToggleState(toggleStateOn);
          handler.sendEmptyMessageDelayed(0, 10);
        }
        if (!isSlipping) {
          // 当手指抬起的时候,应该是让滑块归位的
          if (currentX < bkgSwitchOnWidth - btnSlipWidth) {
            toggleStateOn = false;
          } else {
            toggleStateOn = true;
          }
          postInvalidate();

        }
        break;
    }

    invalidate();//重绘
    return true;

  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //用来记录我们滑动块的位置
//        int left_slip = 0;
    /*限制滑动范围*/
    lineStart = 0;
    lineEnd = bkgSwitchOn.getWidth();
    currentX = currentX > lineEnd ? lineEnd : currentX;
    currentX = currentX < lineStart ? lineStart : currentX;

    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;
//            }
      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();
    }

    handler.sendEmptyMessageDelayed(0, 10);
    //绘制图像
    canvas.drawBitmap(btnSlip, left_slip, 0, paint);
  }

  //计算开关的宽高
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight());
  }

  /**
   * 设置图片资源信息
   */
  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());
    //获取背景宽度
    bkgSwitchOnWidth = bkgSwitchOn.getWidth();
    btnSlipWidth = btnSlip.getWidth();
  }

  /**
   * 设置开关按钮的状态
   */
  public void setToggleState(boolean state) {
    toggleStateOn = state;
  }

  public void setOnToggleStateListener(OnToggleStateListener listener) {
    toggleStateListener = listener;
    isToggleStateListenerOn = true;
  }


  /**
   * 自定义开关状态监听器
   */


  public interface OnToggleStateListener {

    abstract void onToggleState(boolean state);
  }

  //设置开关监听器并将是否设置了开关监听器设置为true
  /**
   * 通过handler来控制滑块在开启监护的时候,平缓的滑动到左端
   */
  Handler handler = new Handler() {
    public void handleMessage(android.os.Message msg) {
      if (msg.what == 0) {
        // 如果x还大于0,就人为的设置缓慢移动到最左端,每次移动距离设置为背景宽的/100
        if (currentX > 0) {
          currentX = currentX - bkgSwitchOnWidth * 1.0f / 100;
//                    left_slip=(int) currentX;
          // 刷新界面
          postInvalidate();
          // 设置继续移动
          handler.sendEmptyMessageDelayed(0, 10);
        } else {
          handler.removeCallbacksAndMessages(null);
          currentState = isSlipping;
        }
      }
    }

    ;
  };

}
 
 
 
 

调用
//设置滑动图片和背景
toggle.setImageRes(R.drawable.bg_slide, R.drawable.bg_slide, R.drawable.bt_hk);

// 设置开关的默认状态 true开启状态
toggle.setToggleState(false);
//设置监听
toggle.setOnToggleStateListener(this);


上述的有参考其他大神的代码,根据字的项目做得,如果有需要,可以改成自己的项目需要的样式,此开关开启功能,我还做了seekbar的有时间我会把用seekbar做得贴上去,第一次写,写的不好。希望有大神能指导一下。

猜你喜欢

转载自blog.csdn.net/sinat_36345777/article/details/80745968