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實現滑動驗證效果的文章就介紹到這瞭,更多相關Android自定View滑動驗證內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: