ToggleButton
效果:
之前项目用到toggleButton,但是用的是别人的开源控件。。。现在比以前技术好一点,就想说自定义一个。。。结果发现通过属性动画很简单的就把效果实现了。。。因为难度不高,就不分开讲解,注释也比较清楚。。下面是具体代码:
public class ToggleButton extends View implements View.OnClickListener{
/*
打开时的画笔
*/
private Paint mOnPaint;
/*
关闭时的画笔
*/
private Paint mOffPaint;
/*
游标的画笔
*/
private Paint mFrontPaint;
/*
是否打开的布尔值
*/
private boolean isCheck = false;
/*
因为在onDraw里面最好不要实例化对象,所以定义为成员变量
rectBack:背景框的矩形
rectFront:前景框的矩形
*/
private RectF rectBack;
private RectF rectFront;
/*
关闭时的颜色
*/
private int mOffColor = 0Xffcccad2;
/*
打开时的颜色
*/
private int mOnColor = 0xff01c78f;
/*
游标的颜色
*/
private int mCircleColor = 0xfff5f5f5;
/*
游标和边界的间距
*/
private float circlePadding;
/*
游标中心X坐标
*/
private float start;
public ToggleButton(Context context) {
this(context, null, 0);
}
public ToggleButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mOnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOffPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFrontPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
rectBack = new RectF();
rectFront = new RectF();
circlePadding = dpToPx(2);
setOnClickListener(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//默认为Exactly
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width * (5/9f));
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//初始化start
start = isCheck ? getWidth() - (getHeight() / 2f) : getHeight()/2f;
}
public void setCheck(boolean isCheck) {
this.isCheck = isCheck;
}
public void setOffColor(int mOffColor) {
this.mOffColor = mOffColor;
}
public void setOnColor(int mOnColor) {
this.mOnColor = mOnColor;
}
public void setCircleColor(int mCircleColor) {
this.mCircleColor = mCircleColor;
}
public void setCirclePadding(int dp) {
this.circlePadding = dpToPx(dp);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置画笔颜色
mOnPaint.setColor(mOnColor);
mOffPaint.setColor(mOffColor);
mFrontPaint.setColor(mCircleColor);
float backStartX = getHeight()/2f;
//画背景的圆角矩形
rectBack.set(0, 0, getWidth(), getHeight());
canvas.drawRoundRect(rectBack, backStartX, backStartX, mOffPaint);
//画前景的圆角矩形,当处于关闭状态时不画
if (start!=backStartX) {
rectFront.set(0, 0, start + backStartX, getHeight());
canvas.drawRoundRect(rectFront, backStartX, backStartX, mOnPaint);
}
//画游标
canvas.drawCircle(start, getHeight() / 2f, getHeight() / 2f - circlePadding, mFrontPaint);
}
/*
打开时调用动画
*/
private void checkOn(){
ValueAnimator animator = ValueAnimator.ofFloat(getHeight() / 2f, getWidth() - (getHeight() / 2f));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
start = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (onCheckedListener!=null) {
onCheckedListener.checkFinish(true);
}
}
});
animator.setDuration(200);
animator.start();
}
/*
关闭时调用动画
*/
private void checkOff(){
ValueAnimator animator = ValueAnimator.ofFloat(getWidth() - (getHeight() / 2f), getHeight() / 2f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
start = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (onCheckedListener!=null) {
onCheckedListener.checkFinish(false);
}
}
});
animator.setDuration(200);
animator.start();
}
/*
将dp转换为px
*/
private float dpToPx(int dp){
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
}
private OnCheckedListener onCheckedListener;
/*
设置接口
*/
public void setOnCheckedListener(OnCheckedListener checkedListener) {
this.onCheckedListener = checkedListener;
}
/*
定义一个接口,分别是打开时和关闭时调用
*/
public interface OnCheckedListener{
void checkFinish(boolean isCheck);
}
/*
监听点击
*/
@Override
public void onClick(View v) {
if (!isCheck) {
checkOn();
} else {
checkOff();
}
isCheck = !isCheck;
}
}