自定义组件之滑动开关
/**
* @author WuMeng
* @date 2019/1/2
* Describe:
* 一个视图从创建到显示过程中的主要方法:
* 1. 构造方法实例化类
* 2. 测量-measure(int,int)---> onMeasure();
* 如果当前View是一个ViewGroup,还有义务测量孩子,孩子有建议权
* 3. 指定位置-layout()---> onLayout();
* 指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
* 4. 绘制视图-draw()---> onDraw()
* 根据上面两个方法参数,进行绘制
*
*/
public class MyToggleButton extends View implements View.OnClickListener {
/**
* 背景图
*/
private Bitmap backgroundBitmap;
/**
* 上面的滑块
*/
private Bitmap slideBitmap;
/**
* 画笔
*/
private Paint paint;
/**
* 距离左边的最大距离
*/
private int slideLeftMax;
/**
* 开关是否打开
*/
private boolean isOpen = false;
/**
* 距离左边的距离
*/
private int slideLeft;
/**
* 在代码中new实例化时调用
* @param context
*/
public MyToggleButton(Context context) {
super(context);
}
/**
* 在布局文件中声明View的时候,该方法由系统调用
* 如果我们在布局文件中使用该类,将会使用这个构造方法实例化该类,如果没有就崩溃
* @param context
* @param attrs
*/
public MyToggleButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
/**
* 增加一个默认显示样式时候使用
* @param context
* @param attrs
* @param defStyleAttr
*/
public MyToggleButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void initView() {
paint = new Paint();
// 设置抗锯齿
paint.setAntiAlias(true);
// 图片解析为Bitmap
backgroundBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.switch_background);
slideBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.slide_button);
slideLeftMax = backgroundBitmap.getWidth() - slideBitmap.getWidth();
// 设置点击事件
this.setOnClickListener(this);
}
/**
* 视图的测量
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 保存测量结果
setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
}
/**
* 视图的绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(backgroundBitmap,0,0,paint);
canvas.drawBitmap(slideBitmap,slideLeft,0,paint);
}
@Override
public void onClick(View v) {
if (isEnableClick) {
isOpen = !isOpen;
flushView();
}
}
private float startX;
private float lastX;
private boolean isEnableClick = true;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 1.记录按下的坐标
lastX = startX = event.getX();
isEnableClick = true;
break;
case MotionEvent.ACTION_MOVE:
// 2. 计算结束值
float endX = event.getX();
// 3. 计算偏移量
float distanceX = endX - startX;
slideLeft = (int) (slideLeft + distanceX);
// 4.屏蔽非法值
if (slideLeft < 0) {
slideLeft = 0;
} else if (slideLeft > slideLeftMax) {
slideLeft = slideLeftMax;
}
// 5. 刷新
invalidate();
// 6. 数据还原
startX = event.getX();
if (Math.abs(endX - lastX) > 5) {
isEnableClick = false;
}
break;
case MotionEvent.ACTION_UP:
if (!isEnableClick) {
if (slideLeft > slideLeftMax / 2) {
isOpen = true;
} else if (slideLeft < slideLeftMax / 2){
isOpen = false;
}
flushView();
}
break;
default:
break;
}
return true;
}
private void flushView() {
if (isOpen) {
slideLeft = slideLeftMax;
} else {
slideLeft = 0;
}
// 会导致onDraw()重新被调用
invalidate();
}
}