要求:1.可以点击响应开关
2.手指可以滑动开关,放手后回弹到贴近的一侧
/**
* Created by huanmeiqi on 2016/08/19.
* Describe 自定义开关
* 步骤
* 1.重构3个构造方法
* 2.定义initView(),完成加载BitMap、设置画笔等操作
* 3.重写OnMearsue,用setMeasuredDimension方法设置View的宽高
* 4.重写OnDraw(),完成绘制
* 5.重写OnTouchEvent()完成滑动回调
* 6.设置点击事件监听
* 7.解决点击与滑动的冲突
*/
public class SwitchView extends View implements View.OnClickListener{
private Context context;
private Bitmap back_bitmap;
private Bitmap button_bitmap;
private Paint paint;
private int back_width;
private int button_width;
private int height;
/*
滑动按钮左边相对View的距离
*/
private float alignLeft;
/*
滑动按钮左边相对View的最大距离
*/
private int alignLeftMax;
private float startX;
private float endX;
private float moveX;
/*
默认switch为打开状态
*/
private boolean isSwitchOpen = true;
/*
默认switch可以点击
*/
private boolean isEnClick = true;
/*
重构三个构造方法
*/
public SwitchView(Context context) {
this(context,null);
}
public SwitchView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SwitchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
initView();
}
/*
初始化操作
*/
private void initView() {
//获取开关背景图片
back_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
//获取滑动按钮图片
button_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
//获取图片的宽高,两张图的高度一致
back_width = back_bitmap.getWidth();
button_width = button_bitmap.getWidth();
height = button_bitmap.getHeight();
//滑动按钮左边相对View的最大距离
alignLeftMax = back_width - button_width;
alignLeft = alignLeftMax;
//创建并设置画笔
paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
//设置点击事件的监听
setOnClickListener(this);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN : //手指按下
//记下初始按下位置
startX = event.getX();
break;
case MotionEvent.ACTION_MOVE : //手指滑动
//再次记下滑动过程的位置
endX = event.getX();
//计算滑动的距离
moveX = endX - startX;
alignLeft += moveX;//更新左边的相对距离
startX = endX;//实时更新起始坐标
//屏蔽非法值
if(alignLeft < 0){
alignLeft = 0;
}else if(alignLeft > alignLeftMax){
alignLeft = alignLeftMax;
}
//更新
invalidate();//调用它,会重新执行OnDraw()
break;
case MotionEvent.ACTION_UP : //手指抬起,需要它回弹到“开”或者“关”的状态。还要在这里解决事件冲突
if(Math.abs(moveX) > 0){//有滑动的情况,修改不能点击
isEnClick = false;
if(Math.abs(alignLeft) < alignLeftMax/2){
alignLeft = 0;
}else if(Math.abs(alignLeft) > alignLeft/2){
alignLeft = alignLeftMax;
}else if(Math.abs(alignLeft) == alignLeftMax/2){
alignLeft = 0;
}
invalidate();
}else{
isEnClick = true;//否则,修改为可以点击
}
break;
}
return true;
}
});
}
/*
设置View的宽高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//View的宽高就是背景图片的宽高
setMeasuredDimension(back_width,height);
}
/*
绘制View
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(back_bitmap,0,0,paint);//背景图左顶点与View的左顶点重合
canvas.drawBitmap(button_bitmap,alignLeft,0,paint);//滑动按钮相对View左边距离是不断变动的
}
/*
设置点击事件的监听
*/
@Override
public void onClick(View v) {
if(isEnClick){
if(isSwitchOpen){
alignLeft = 0;
}else{
alignLeft = alignLeftMax;
}
isSwitchOpen = !isSwitchOpen;//改变状态
invalidate();//重绘
}
}
}