您的位置:首页 > 其它

自定义View实现SwichButton效果

2016-04-04 23:56 363 查看


老习惯先看效果,这种效果其实用自定义的CheckBox也是很好实现的。但是这样实现可以用手指滑动实现和手指点击实现。

需要掌握的技术

自定义属性

触摸事件的处理

回调的使用

实现步骤

自定义属性

怎么自定义属性我就不详细介绍了网上一大堆,这里需要现在资源文件夹下的values创建attrs.xml文件,主要定义了默认是否是选中和滑动的图片是什么。

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SwitchView">
<attr name="check" format="boolean" />
<attr name="beforeBg" format="reference"/>
</declare-styleable>
</resources>


编写SwitchView控件继承View

2.1 获取自定义属性

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);
isCheck = attrs.getAttributeBooleanValue(R.styleable.SwitchView_check, false);
slideButton = attrs.getAttributeResourceValue(R.styleable.SwitchView_beforeBg, R.mipmap.slide_button);
initView();
}


2.2 将资源文件转换为Bitmap(按钮底部的背景通过Canvas在上面画图)

//将资源图片转换为Bitmap
bitmapSlide = BitmapFactory.decodeResource(getResources(), slideButton);
bgBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_background);


2.3 计算滑块离左右两边的距离

//计算离左边的最大距离
MAX_LEFT = bgBitmap.getWidth() - bitmapSlide.getWidth();
if (isCheck) {
mSlideLeft = MAX_LEFT;
} else {
mSlideLeft = 0;
}


2.4 将背景图和滑块通过画布画出来

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgBitmap, 0, 0, null);  //绘制底部背景
canvas.drawBitmap(bitmapSlide, mSlideLeft, 0, null);  //绘制滑块
}


2.5 监听触摸事件

这里需要做的事是根据滑动的x轴的坐标来改变滑块的位置,但是需要注意的是当滑动的x轴的坐标小于0或者滑动的坐标已经大于最大能一定的值就是MAX_LEFT需要自己设置滑块的位置为0或者MAX_LEFT。这里主要监听的是MotionEvent.ACTION_MOVE方法

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//手指按下时获取x的起点坐标
startX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
//移动时获取手指移动x的最后坐标
endX = event.getX();
float dx = endX - startX;
moveX = moveX + (int) Math.abs(dx);
mSlideLeft = mSlideLeft + (int) dx;
//防止超过边界
if (mSlideLeft < 0) {
mSlideLeft = 0;
} else if (mSlideLeft > MAX_LEFT) {
mSlideLeft = MAX_LEFT;
}
invalidate();
startX = endX;
break;
case MotionEvent.ACTION_UP:
Log.e("CXX", "moveX" + moveX);
if (moveX > 5) {
isClick = false;
} else {
isClick = true;
}
moveX = 0;
if (!isClick) {
if (mSlideLeft < MAX_LEFT / 2) {
mSlideLeft = 0;
isCheck = false;
} else {
mSlideLeft = MAX_LEFT;
isCheck = true;
}
if (onCheckListener != null) {
onCheckListener.onCheck(SwitchView.this, isCheck);
}
}

invalidate();
break;
}
return super.onTouchEvent(event);
}


代码解释下isClick的意识这个是和下面即将写的onClick事件关联在一起的因为我们的代码是可以滑动和点击共同存在的所以需要做个判断。如果不做判断会出现这么一个情况,就是我将滑块从左边滑动到右边不松手在滑动到左边按照道理是应该停留在左边的但是因为写了onClick事件所以还会调onClick中的事件故在这里加了个判断。

onClick中代码如下:

@Override
public void onClick(View v) {
if (!isClick) {
return;
}
Log.e("CXX", "click" + isCheck);
if (isCheck) {
mSlideLeft = 0;
isCheck = false;
} else {
mSlideLeft = MAX_LEFT;
isCheck = true;
}
Log.e("CXX", "onCheck" + onCheckListener);
//选中的回调
if (onCheckListener != null) {
onCheckListener.onCheck(SwitchView.this, isCheck);
}
invalidate();
}


2.6 回调事件

定义一个接口

public void setOnCheckListener(OnCheckListener onCheckListener) {
this.onCheckListener = onCheckListener;
}

public interface OnCheckListener {
public void onCheck(View view, boolean isCheck);
}


最后是整个SwitchView的源码:

package com.media;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
* Created by CXX on 2016/4/4.
*/
public class SwitchView extends View implements View.OnClickListener {

private boolean isCheck; //当前滑动开关状态
private int slideButton; //滑动图片资源文件
private Bitmap bitmapSlide; //滑动图片Bitmap
private Bitmap bgBitmap; //背景图片资源文件
private int MAX_LEFT; //滑动最大左边距
private int mSlideLeft; //当前滑块左边距
private float startX;
private float endX;
private int moveX;
private boolean isClick = false; //是否可以点击

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);
isCheck = attrs.getAttributeBooleanValue(R.styleable.SwitchView_check, false);
slideButton = attrs.getAttributeResourceValue(R.styleable.SwitchView_beforeBg, R.mipmap.slide_button);
initView();
}

private void initView() {
Log.e("CXX", "isCheck" + isCheck);
//将资源图片转换为Bitmap
bitmapSlide = BitmapFactory.decodeResource(getResources(), slideButton);
bgBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_background);
//计算离左边的最大距离
MAX_LEFT = bgBitmap.getWidth() - bitmapSlide.getWidth();
if (isCheck) {
mSlideLeft = MAX_LEFT;
} else {
mSlideLeft = 0;
}
//刷新界面
invalidate();
setOnClickListener(this);
}

@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //手指按下时获取x的起点坐标 startX = event.getX(); break; case MotionEvent.ACTION_MOVE: //移动时获取手指移动x的最后坐标 endX = event.getX(); float dx = endX - startX; moveX = moveX + (int) Math.abs(dx); mSlideLeft = mSlideLeft + (int) dx; //防止超过边界 if (mSlideLeft < 0) { mSlideLeft = 0; } else if (mSlideLeft > MAX_LEFT) { mSlideLeft = MAX_LEFT; } invalidate(); startX = endX; break; case MotionEvent.ACTION_UP: Log.e("CXX", "moveX" + moveX); if (moveX > 5) { isClick = false; } else { isClick = true; } moveX = 0; if (!isClick) { if (mSlideLeft < MAX_LEFT / 2) { mSlideLeft = 0; isCheck = false; } else { mSlideLeft = MAX_LEFT; isCheck = true; } if (onCheckListener != null) { onCheckListener.onCheck(SwitchView.this, isCheck); } } invalidate(); break; } return super.onTouchEvent(event); }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(bgBitmap.getWidth(), bgBitmap.getHeight());
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgBitmap, 0, 0, null); //绘制底部背景
canvas.drawBitmap(bitmapSlide, mSlideLeft, 0, null); //绘制滑块
}

@Override public void onClick(View v) { if (!isClick) { return; } Log.e("CXX", "click" + isCheck); if (isCheck) { mSlideLeft = 0; isCheck = false; } else { mSlideLeft = MAX_LEFT; isCheck = true; } Log.e("CXX", "onCheck" + onCheckListener); //选中的回调 if (onCheckListener != null) { onCheckListener.onCheck(SwitchView.this, isCheck); } invalidate(); }

private OnCheckListener onCheckListener;

public void setOnCheckListener(OnCheckListener onCheckListener) {
this.onCheckListener = onCheckListener;
}

public interface OnCheckListener {
public void onCheck(View view, boolean isCheck);
}
}


源码地址

源码地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: