安卓自定View实现滑动验证效果
Posted NoNullPoint
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓自定View实现滑动验证效果相关的知识,希望对你有一定的参考价值。
效果图
自定义属性代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCheckView">
<attr name="m_blockBg" format="reference" /><!--滑块背景图片-->
<attr name="m_blockColor" format="color" /><!--滑块颜色-->
<attr name="m_blockShadowLayer" format="color" /><!--滑块阴影颜色-->
<attr name="m_proColor" format="color" /><!--进度条颜色-->
<attr name="m_recColor" format="color" /><!--矩形背景色-->
<attr name="m_circleSize" format="integer" /><!--圆角角度值-->
</declare-styleable>
</resources>
自定义View代码
public class MyCheckView extends View
private boolean isBlockArea = false;
private boolean isMove = false;
private boolean isFinish = false;
private boolean isDown = false;
private int mRight;
private int startX = 0;
/**
* 滑块边距
*/
private final int blockSize = SizeUtils.dp2px(5);
/**
* 相关属性
*/
private int m_blockColor = Color.WHITE;//默认滑块颜色
private int m_blockShadowLayer = Color.parseColor("#D8D8D8");//默认滑块阴影色
private int m_proColor = Color.parseColor("#ff3159");//默认进度条颜色
private int m_recColor = Color.parseColor("#D8D8D8");//默认矩形颜色
private int blockDrawableId;//默认滑块背景图
/**
* 矩形画笔
*/
private final Paint recPaint = new Paint();
/**
* 进度条画笔
*/
private final Paint proPaint = new Paint();
/**
* 滑块画笔
*/
private final Paint blockPaint = new Paint();
/**
* 圆角角度
*/
private int circleSize = SizeUtils.dp2px(20);
/**
* 记录父控件宽度
*/
private float parentWidth = 0f;
/**
* 矩形高度
*/
private int proHeight;
/**
* 默认高度
*/
private final int DEFAULT_HEIGHT = SizeUtils.dp2px(45);
/**
* 滑块宽度
*/
private final int blockWidth = SizeUtils.dp2px(60);
/**
* 手指落下位置
*/
private int dX;
/**
* 偏移距离
*/
private int mX;
/**
* 接口回调
*/
private FinishListener finishListener;
public void setFinishListener(FinishListener finishListener)
this.finishListener = finishListener;
public MyCheckView(@NonNull Context context)
super(context);
init();
public MyCheckView(@NonNull Context context, @Nullable AttributeSet attrs)
super(context, attrs);
initParams(context, attrs);
init();
public MyCheckView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
initParams(context, attrs);
init();
/**
* 初始化自定义属性
*
* @param context 上下文
* @param attrs 属性参数
*/
private void initParams(Context context, AttributeSet attrs)
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCheckView);
if (typedArray != null)
//获取滑块背景图片
blockDrawableId = typedArray.getResourceId(R.styleable.MyCheckView_m_blockBg, -1);
//获取滑块颜色
m_blockColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_blockColor);
//滑块阴影色
m_blockShadowLayer = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_blockShadowLayer);
//进度条颜色
m_proColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_proColor);
//矩形颜色
m_recColor = typedArray.getColor(R.styleable.MyCheckView_m_blockColor, m_recColor);
//圆角角度值
circleSize = typedArray.getInt(R.styleable.MyCheckView_m_blockColor, circleSize);
typedArray.recycle();
/**
* 初始化画笔
*/
private void init()
//设置矩形背景色
recPaint.setColor(m_recColor);
recPaint.setStyle(Paint.Style.FILL);
recPaint.setAntiAlias(true);
//设置进度条背景色
proPaint.setColor(m_proColor);
proPaint.setStyle(Paint.Style.FILL);
recPaint.setAntiAlias(true);
//判断是否使用了背景图
if (blockDrawableId != -1)
//设置滑块背景色
blockPaint.setColor(m_blockColor);
blockPaint.setStyle(Paint.Style.FILL_AND_STROKE);
blockPaint.setAntiAlias(true);
//给滑块添加阴影
blockPaint.setShadowLayer(35, 1, 1, m_blockShadowLayer);
else
blockPaint.setStyle(Paint.Style.FILL_AND_STROKE);
blockPaint.setAntiAlias(true);
public void blockReset()
mX = 0;
reset(startX);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
parentWidth = getMyWSize(widthMeasureSpec);
proHeight = getMyHSize(heightMeasureSpec);
setMeasuredDimension((int) parentWidth, proHeight);
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
//绘制矩形
RectF rectF = new RectF();
rectF.left = 1;
rectF.right = parentWidth - 1;
rectF.top = 1;
rectF.bottom = proHeight - 1;
//绘制圆角矩形
canvas.drawRoundRect(rectF, circleSize, circleSize, recPaint);
if (isMove || isDown)
//绘制进度条
RectF rectP = new RectF();
rectP.left = 1;
rectP.right = blockWidth + blockSize + mX;
rectP.top = 1;
rectP.bottom = proHeight - 1;
canvas.drawRoundRect(rectP, circleSize, circleSize, proPaint);
//绘制滑块
RectF rectB = new RectF();
rectB.left = blockSize + mX;
rectB.right = blockWidth + mX;
rectB.top = blockSize;
rectB.bottom = proHeight - blockSize;
mRight = (int) rectB.right;
//判断是否使用了背景图
if (blockDrawableId != -1)
//绘制背景图
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), blockDrawableId);
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, rect, rectB, blockPaint);
else
//绘制滑块
canvas.drawRoundRect(rectB, circleSize, circleSize, blockPaint);
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event)
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
dX = (int) event.getX();
int dY = (int) event.getY();
int top = getTop();
int bottom = getBottom();
//判断区域是否为滑块
if (dX > blockSize && dX < blockWidth && dY > blockSize && dY < (bottom - top))
isBlockArea = true;
return true;
case MotionEvent.ACTION_MOVE:
if (isBlockArea)
mX = (int) event.getX() - dX;
//设置范围
if ((blockWidth + blockSize + mX) < parentWidth && (blockSize + mX) >= blockSize)
//计算偏移量
invalidate();
startX = (int) event.getX() - blockWidth / 2;
else if ((blockSize + mX) >= blockSize)
//超出复位
mX = (int) parentWidth - blockWidth - blockSize;
invalidate();
isMove = true;
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isBlockArea = false;
isFinish = mRight == parentWidth - blockSize;
if (isFinish)
//监听回调
if (finishListener != null)
finishListener.finish();
if (!isFinish && isMove)
reset(startX);
break;
return super.onTouchEvent(event);
/**
* 松手回弹动画效果
*/
private void reset(int start)
ValueAnimator valueAnimator = ValueAnimator.ofInt(start, 0);
valueAnimator.setDuration(500);
valueAnimator.start();
valueAnimator.addUpdateListener(animation ->
mX = (int) animation.getAnimatedValue();
//刷新
invalidate();
);
valueAnimator.addListener(new AnimatorListenerAdapter()
@Override
public void onAnimationEnd(Animator animation)
isMove = false;
isFinish = false;
startX = 0;
);
/**
* 获取测量大小
*/
private int getMyWSize(int measureSpec)
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
result = specSize;//确切大小,所以将得到的尺寸给view
else if (specMode == MeasureSpec.AT_MOST)
result = Math.min(getScreenWidth() - 20, specSize);
else
result = getScreenWidth() - 20;
return result;
/**
* 获取测量大小
*/
private int getMyHSize(int measureSpec)
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
result = specSize;//确切大小,所以将得到的尺寸给view
else if (specMode == MeasureSpec.AT_MOST)
result = Math.min(DEFAULT_HEIGHT, specSize);
else
result = DEFAULT_HEIGHT - 20;
return result;
/**
* 获取屏幕宽度
*/
private int getScreenWidth()
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
/**
* 接口回调方法
*/
public interface FinishListener
void finish();
使用方法
<com.guanwei.globe.view.MyCheckView
android:id="@+id/checkView"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:m_blockBg="@mipmap/block" />
以上是关于安卓自定View实现滑动验证效果的主要内容,如果未能解决你的问题,请参考以下文章