本篇内容主要讲解“Android如何自定View实现滑动验证效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android如何自定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" />
到此,相信大家对“Android如何自定View实现滑动验证效果”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。