Android自定义View仿IOS选择控件Togglebutton实现
程序员文章站
2022-05-25 08:21:49
...
Android自定义View仿IOS选择控件Togglebutton实现
目前在搞自定义view这一块的东西,将自己手写的很多效果控件将全部展示在博客中,这个是模仿ios的一个控件,虽然有原生的可以直接用了,但是毕竟知道实现更有助于自己写出风格各样的自定义控件。文中会贴出代码,但如果想在实际项目中使用,还需要增加很多逻辑判断以及监听回掉。
原效果图如下:
画图分析
自定义view的绘制最重要的是分析状态以及过程,最好使用笔纸将所需完成的控件画出来,这样可以很清楚的描述出我们的绘制过程,以下是我的绘制理解:
以上即为描绘的几种状态:
原始状态:控件没被选择的状态,圆在左边;
选择点击状态:即点击后发生的状态显示;绿色的圆会往右移动,蓝色框中的白色区域会缩小,选中状态的红颜色会出现,圆在最右边时,白色完全消失;
选择完成状态:蓝色框中的白色区域撤底消失,选中状态的颜色一直出现,圆在右边;
取消选择点击状态:蓝色框中的白色区域会增大,圆会一直往左移动,圆到最左边时白色盖住红色;
代码实现
代码很简单,主要是对设计思路的分析
public class Togglebutton extends View {
private Region regionClip,regionClick;//点击的截取区域
private Path pathRoundOut,pathCircleOut,pathCircleIn,pathRoundIn_normal,getPathRoundIn_select;//路径
private Paint paintRoundOut,paintRoundInNormal,paintRoundInSelect,paintCircleIn,paintCircleOut;//画笔
private float varySet;//动画的变化值
private float roundOutWidth=120f,roundOutHeight=60f,circleRadio=28f;//控件的参数
private int mHeight,mWidth;//画布的宽高
private boolean choice=false,inner=false;//用来判断事件的句柄
private ValueAnimator animatorOpen,animatorClose;//动画
private Matrix matrix;//矩阵
private float[] dst=new float[2];//当前点击的点
public Togglebutton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint();
initValueAnimator();
matrix=new Matrix();
}
/**
* 初始化画笔
*/
private void initPaint() {
paintCircleIn=new Paint();
paintCircleIn.setStyle(Paint.Style.FILL);
paintCircleIn.setColor(Color.WHITE);
paintCircleIn.setAntiAlias(true);
paintCircleOut=new Paint();
paintCircleOut.setAntiAlias(true);
paintCircleOut.setStyle(Paint.Style.STROKE);
paintCircleOut.setStrokeWidth(1);
paintCircleOut.setColor(Color.parseColor("#8a8a8a"));
paintRoundOut=new Paint();
paintRoundOut.setColor(Color.parseColor("#8a8a8a"));
paintRoundOut.setAntiAlias(true);
paintCircleOut.setStyle(Paint.Style.STROKE);
paintCircleOut.setAntiAlias(true);
paintCircleOut.setStrokeWidth(1);
paintRoundInNormal=new Paint();
paintRoundInNormal.setAntiAlias(true);
paintRoundInNormal.setStyle(Paint.Style.FILL);
paintRoundInNormal.setColor(Color.WHITE);
paintRoundInSelect=new Paint();
paintRoundInSelect.setStyle(Paint.Style.FILL);
paintRoundInSelect.setAntiAlias(true);
paintRoundInSelect.setColor(Color.BLUE);
}
/**
* 初始化路径
*/
private void initPath() {
pathCircleIn=new Path();
pathCircleOut=new Path();
pathRoundOut=new Path();
pathRoundIn_normal=new Path();
getPathRoundIn_select=new Path();
pathRoundOut.addRoundRect(new RectF(-roundOutWidth/2,-roundOutHeight/2,roundOutWidth/2,roundOutHeight/2),circleRadio+1,circleRadio+1, Path.Direction.CW);
pathRoundIn_normal.addRoundRect(new RectF(-roundOutWidth / 2 + varySet, -roundOutHeight / 2 + varySet / 2, roundOutWidth / 2 - varySet, roundOutHeight / 2 - varySet / 2), circleRadio, circleRadio, Path.Direction.CW);
pathCircleIn.addCircle(-roundOutWidth/4+varySet,0,circleRadio, Path.Direction.CW);
pathCircleOut.addCircle(-roundOutWidth/4+varySet,0,circleRadio+1, Path.Direction.CW);
getPathRoundIn_select.addRoundRect(new RectF(-roundOutWidth/2,-roundOutHeight/2,roundOutWidth/2,roundOutHeight/2),circleRadio,circleRadio, Path.Direction.CW);
regionClick=new Region();
regionClick.setPath(pathRoundOut,regionClip);
}
/**
* 初始化动画
*/
private void initValueAnimator() {
animatorOpen = ValueAnimator.ofFloat(0,roundOutWidth/2);
animatorOpen.setRepeatCount(0);
animatorOpen.setDuration(500);
animatorOpen.setInterpolator(new LinearInterpolator());
animatorOpen.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
varySet= (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
animatorClose = ValueAnimator.ofFloat(roundOutWidth/2,0);
animatorClose.setRepeatCount(0);
animatorClose.setDuration(500);
animatorClose.setInterpolator(new LinearInterpolator());
animatorClose.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
varySet= (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight=h;
mWidth=w;
//获取手势的剪裁区域
regionClip=new Region(-mWidth,-mHeight,mWidth,mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画布平移
canvas.translate(mWidth/2,mHeight/2);
initPath();
matrix.reset();
if(matrix.isIdentity()){
//由于画布平移了,矩阵要相应变换,对区域的判断坐标会出问题
canvas.getMatrix().invert(matrix);
}
drawPath(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
dst[0]=event.getRawX();
dst[1]=event.getRawY();
matrix.mapPoints(dst);
//判断手势是否在画的圆角区域内
inner=regionClick.contains((int)dst[0],(int) dst[1]);
break;
case MotionEvent.ACTION_UP:
dst[0]=event.getRawX();
dst[1]=event.getRawY();
matrix.mapPoints(dst);
//判断手势是否离开
if(inner&®ionClick.contains((int)dst[0],(int) dst[1])){
if(animatorOpen.isRunning()){
animatorOpen.cancel();
}
if (animatorClose.isRunning()){
animatorClose.cancel();
}
choice=!choice;
if(choice){
animatorOpen.start();
}else {
animatorClose.start();
}
}
break;
default:break;
}
return true;
}
/**
* 画
* @param canvas
*/
private void drawPath(Canvas canvas) {
if(choice){
canvas.drawPath(pathRoundOut,paintRoundInSelect);
}else {
canvas.drawPath(pathRoundOut,paintRoundOut);
}
canvas.drawPath(getPathRoundIn_select,paintRoundInSelect);
canvas.drawPath(pathRoundIn_normal,paintRoundInNormal);
canvas.drawPath(pathCircleOut,paintCircleOut);
canvas.drawPath(pathCircleIn,paintCircleIn);
}
}
效果展示
抠脚来的,不喜勿喷
上一篇: 开发idea插件教程
下一篇: 把知乎丁香医生的文章及回答转pdf