效果图
自定义属性代码
<?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();
}
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" />
到此这篇关于Android自定View实现滑动验证效果的文章就介绍到这了,更多相关Android自定View滑动验证内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!