千家信息网

Android如何自定View实现滑动验证效果

发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,本篇内容主要讲解"Android如何自定View实现滑动验证效果",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Android如何自定View实现滑动验证效
千家信息网最后更新 2025年01月25日Android如何自定View实现滑动验证效果

本篇内容主要讲解"Android如何自定View实现滑动验证效果",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Android如何自定View实现滑动验证效果"吧!

效果图

自定义属性代码

                                                        

自定义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();    }}

使用方法

到此,相信大家对"Android如何自定View实现滑动验证效果"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0