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做得贴上去,第一次写,写的不好。希望有大神能指导一下。