自定义控件 - 切换开关:SwitchView
自定义控件一般的几个步骤:
1.初始化相关背景图片,布局文件,自定义属性
2.设置控件宽高OnMeasure()
3.布局或者排版OnLayout()
4.绘制控件OnDraw()
5.处理触摸事件OnTouchEvent()
1 public class SwitchView extends View implements View.OnTouchListener { 2 3 //开关状态图片 4 private Bitmap mSwitch_on, mSwitch_off, mSwitch_circle; 5 6 //开关状态 默认关闭 7 private boolean mCurrentState = false; 8 9 //开关切换回调接口 10 private OnSwitchChangedListener mOnSwitchChangedListener; 11 12 //X轴按下坐标 13 private int downX; 14 //X轴移动时触点坐标 15 private int moveX; 16 //X轴偏移量 17 private int left = 0; 18 //最大可移动距离 19 private int max; 20 21 public SwitchView(Context context) { 22 super(context); 23 init(); 24 } 25 26 public SwitchView(Context context, AttributeSet attrs) { 27 super(context, attrs); 28 init(); 29 } 30 31 public SwitchView(Context context, AttributeSet attrs, int defStyle) { 32 super(context, attrs, defStyle); 33 init(); 34 } 35 36 //1 初始化图片(加载) 37 private void init() { 38 Resources resr = getResources(); 39 mSwitch_on = BitmapFactory.decodeResource(resr, R.mipmap.switch_on); 40 mSwitch_off = BitmapFactory.decodeResource(resr, R.mipmap.switch_off); 41 mSwitch_circle = BitmapFactory.decodeResource(resr, R.mipmap.switch_circle); 42 setOnTouchListener(this); 43 } 44 45 //2 设置控件宽高(测量) 46 @Override 47 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 48 int widthSize = mSwitch_off.getWidth(); 49 int heightSize = mSwitch_off.getHeight(); 50 max = mSwitch_off.getWidth() - mSwitch_circle.getWidth(); 51 setMeasuredDimension(widthSize, heightSize); 52 } 53 54 //3 布局(排版) 55 @Override 56 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 57 super.onLayout(changed, left, top, right, bottom); 58 } 59 60 //4 最后绘制控件 61 @Override 62 protected void onDraw(Canvas canvas) { 63 super.onDraw(canvas); 64 Matrix m = new Matrix(); 65 Paint p = new Paint(); 66 if (mCurrentState) { 67 canvas.drawBitmap(mSwitch_on, m, p); 68 } else { 69 canvas.drawBitmap(mSwitch_off, m, p); 70 } 71 canvas.drawBitmap(mSwitch_circle, left, 0, p); 72 } 73 74 //5 触摸事件 75 @Override 76 public boolean onTouch(View v, MotionEvent event) { 77 switch (event.getAction()) { 78 case MotionEvent.ACTION_DOWN: 79 downX = (int) event.getX();//初始X轴按下坐标 80 break; 81 case MotionEvent.ACTION_MOVE: 82 moveX = (int) event.getX(); 83 left = moveX - downX; 84 if (!mCurrentState) { 85 //关闭状态边界处理 86 if (left < 0) { 87 left = 0; 88 } else if (left > max) { 89 left = max; 90 } 91 } else { 92 //开启状态边界处理 93 left = moveX - downX; 94 if (left > 0) {//向右滑 95 left = max; 96 } else if (Math.abs(left) > max) { 97 left = 0; 98 } else { 99 left = max - Math.abs(left); 100 } 101 } 102 break; 103 case MotionEvent.ACTION_UP: 104 case MotionEvent.ACTION_CANCEL://抬起时的判断 105 int upX = (int) event.getX(); 106 boolean state = false; //滑动是否成功 107 //1 关闭状态 108 if (!mCurrentState) { 109 //滑动是否成功 110 //a 移动距离超过 1/2 的滑动宽度 111 //b 触摸点在滑动区域,开启按钮 112 state = (moveX - downX) >= max / 2 || upX >= max; 113 if (state) { 114 left = max; 115 mCurrentState = true; 116 } else { 117 left = 0; 118 } 119 } else { 120 //2 开启状态,判断滑动是否成功 121 //a 移动距离超过 1/2 的滑动宽度 122 //b 触摸点在滑动区域,关闭按钮 123 state = (downX - moveX) >= max / 2 || upX <= max; 124 if (state) { 125 left = 0; 126 mCurrentState = false; 127 } else { 128 left = max; 129 } 130 } 131 //滑动成功 且 回调接口不能空 触发回调方法 132 if (state && null != mOnSwitchChangedListener) { 133 mOnSwitchChangedListener.onSwitchChanged(mCurrentState); 134 } 135 break; 136 } 137 invalidate(); 138 return true; 139 } 140 141 //开关切换回调接口 142 public interface OnSwitchChangedListener { 143 void onSwitchChanged(boolean isOpen); 144 } 145 146 public void setOnSwitchChangedListener(OnSwitchChangedListener listener) { 147 this.mOnSwitchChangedListener = listener; 148 } 149 150 public void setCurrentState(boolean isOpen) { 151 mCurrentState = isOpen; 152 left = isOpen ? max : 0; 153 invalidate(); 154 } 155 156 }