自定义滑动验证

滑动验证实现方式有很多,这里是自定义View的方式,通过按住验证图片移动到目标阴影位置完成验证

public class SlidingVerificationView extends View {

    //原图
    private Bitmap bitmap;
    //画笔
    private Paint paint;

    //阴影区域
    private RectF shadowRect;
    //阴影图
    private Bitmap drawBitmap;

    //验证图长度
    private int drawBitmapLength;
    //验证图
    private Bitmap verifyBitmap;
    private RectF moveRect;

    private boolean isMove = false;
    //触摸点X坐标
    private float mX = 0;
    private float mY = 0;

    //随机数
    private Random random;
    //随机坐标
    private int x;
    private int y;

    private int paddingLeft;
    private int paddingRight;
    private int paddingTop;
    private int paddingBottom;

    //控件最大宽高
    private int maxWidth;
    private int maxHeight;

    public SlidingVerificationView(Context context) {
        this(context, null);
    }

    public SlidingVerificationView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlidingVerificationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
        paddingTop = getPaddingTop();
        paddingBottom = getPaddingBottom();

        paint = new Paint();
        paint.setAntiAlias(true);

        shadowRect = new RectF();
        moveRect = new RectF();

        random = new Random();

        screenWidth();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        drawBitmap = null;
        verifyBitmap = null;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap != null) {
            if (drawBitmap == null) {
                //bitmap宽
                int width = getWidth() - paddingLeft - paddingRight;
                //bitmap高
                int height = getHeight() - paddingTop - paddingBottom;
                drawBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);

                if (verifyBitmap == null) {
                    //bitmap最短边长度的四分之一
                    drawBitmapLength = Math.min(drawBitmap.getWidth(), drawBitmap.getHeight()) / 4;
                    //在bitmap上取随即x坐标(drawBitmapLength + paddingLeft到width - drawBitmapLength - paddingRight + paddingLeft),y坐标
                    x = random.nextInt(width - 2 * drawBitmapLength - paddingRight) + drawBitmapLength + paddingLeft;
                    y = random.nextInt(height - 2 * drawBitmapLength - paddingBottom) + drawBitmapLength + paddingTop;
                    //验证的图片
                    verifyBitmap = Bitmap.createBitmap(drawBitmap, x, y, drawBitmapLength, drawBitmapLength);
                }
            }

            //画完整图片
            canvas.drawBitmap(drawBitmap, paddingLeft, paddingTop, paint);

            //画上阴影
            paint.setColor(Color.parseColor("#55000000"));
            shadowRect.set(x + paddingLeft, y + paddingTop, x + drawBitmapLength + paddingLeft, y + drawBitmapLength + paddingTop);
            canvas.drawRect(shadowRect, paint);
            //画验证图片
            paint.setColor(Color.parseColor("#ffffffff"));
            canvas.drawBitmap(verifyBitmap, mX, y + paddingTop, paint);

            moveRect.set(mX, y, mX + drawBitmapLength, y + drawBitmapLength);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        //当模式是MeasureSpec.AT_MOST时,也就是说用户将布局设置成了wrap_content,我们就需要将大小设定为我们计算的数值
        int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);

        //当模式不是MeasureSpec.EXACTLY时设置固定大小
        setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? Math.min(measureWidth, maxWidth) : 600
                , (measureHeightMode == MeasureSpec.EXACTLY) ? Math.min(measureHeight, maxHeight) : 400);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (moveRect.contains(event.getX(), event.getY())) {
                isMove = true;
            }
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (isMove) {
                //获取点击坐标
                mX = event.getX();
                mY = event.getY();
                invalidate();
                return false;
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            performClick();
            return false;
        }
        return true;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    /**
     * 设置滑动验证停止移动时,是否在验证区域
     * 参数range:误差,推荐0.02
     */
    public Boolean setTouchUp(double range) {
        if (isMove) {
            isMove = false;
            float trueX = x + paddingLeft;
            return mX > trueX * (1 - range) && mX < trueX * (1 + range);
        }
        return null;
    }

    /**
     * seekBar验证
     * @param progress
     */
    public void setProgress(float progress){
        isMove = true;
        mX = getWidth()*progress;
        invalidate();
    }

    /**
     * 设置原图
     */
    public void setImageBitmap(@DrawableRes int id) {
        bitmap = getBitmapResources(getResources(), id, false);
        if (drawBitmap != null) {
            drawBitmap.recycle();
            drawBitmap = null;
            verifyBitmap.recycle();
            verifyBitmap = null;
            mX = 0;
        }
        invalidate();
    }

    /**
     * 设置原图
     */
    public void setImageBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        if (drawBitmap != null) {
            drawBitmap.recycle();
            drawBitmap = null;
            verifyBitmap.recycle();
            verifyBitmap = null;
            mX = 0;
        }
        invalidate();
    }

    /**
     * 读取资源文件夹下图片
     *
     * @param res   getResources
     * @param id    文件id
     * @param isRGB 是否使用RGB_565压缩图片
     * @return bitmap
     */
    private Bitmap getBitmapResources(Resources res, int id, boolean isRGB) {
        InputStream is = res.openRawResource(id);
        if (isRGB) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            return BitmapFactory.decodeStream(new BufferedInputStream(is), null, options);
        }
        return BitmapFactory.decodeStream(new BufferedInputStream(is));
    }

    /**
     * 获取屏幕宽高
     */
    private void screenWidth() {
        WindowManager wm = (WindowManager) getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        if (wm != null) {
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            maxWidth = size.x;
            maxHeight = size.y;
        }
    }

}

使用非常简单,只需要设置原图即可,会自动截取某一个区域的图片,并在该位置画上阴影,当验证图片移动到该位置完成验证,验证结果可以监听触摸事件获取,如下所示

//设置图片
slidingVerificationView.setImageBitmap(R.drawable.test)

//验证
slidingVerificationView.setOnTouchListener(object :View.OnTouchListener{
    override fun onTouch(v: View, event: MotionEvent): Boolean {
        if (event.getAction() == MotionEvent.ACTION_UP){
            val isSlidingVerification =  slidingVerificationView.setTouchUp(0.02)
            if (isSlidingVerification != null){
                if (isSlidingVerification){
                    showToast("验证成功")
                }else{
                    showToast("验证失败")
                }
            }
            slidingVerificationView.performClick();
            return true
        }
        return false
    }
})

如果想刷新原图,再次调用setImageBitmap即可

//刷新图片
button2.setOnClickListener {
    slidingVerificationView.setImageBitmap(R.drawable.test)
}

如果想通过进度条的方式拖动验证图片进行验证,使用如下方法即可

        seekBar.max = 100

        seekBar.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                slidingVerificationView.setProgress(progress/100f)
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {

            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                val isSlidingVerification =  slidingVerificationView.setTouchUp(0.02)
                if (isSlidingVerification != null){
                    if (isSlidingVerification){
                        showToast("验证成功")
                    }else{
                        showToast("验证失败")
                    }
                }
            }
        })

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值