安卓自定View实现滑动验证效果

Posted NoNullPoint

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓自定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" />

以上是关于安卓自定View实现滑动验证效果的主要内容,如果未能解决你的问题,请参考以下文章

Android Scroll 滑动效果 及 触摸事件处理

仿探探左右滑动效果(兼容安卓,ios,小程序,h5)

安卓点击按钮实现缩放效果,点击完成恢复原状~~

JS实现安卓手机端触摸屏幕左右滑动显示的效果

自定义View 之利用ViewPager 实现画廊效果(滑动放大缩小)

自定义View 之利用ViewPager 实现画廊效果(滑动放大缩小)