安卓自定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" />

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
)">
下一篇>>