Android 图片滑块解锁 and 组件拖动解锁的简单实现

效果图

这里写图片描述

实现方式

滑块解锁
自定义ImageView  在原图的基础上再画两个 滑块 一个目标位 一个移动位。
通过一个对外方法可以更改进度 然后 调用postInvalidate() 实现该效果  
大致原理就是这样  下面上代码
package project.com.verifyproject;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;

/**
 * Created by 于德海 on 2018/6/7.
 * 
 * email : yudehai0204@163.com
 *
 * @describe
 */

public class SlideValidateView extends AppCompatImageView {
    //Image背景图
    private Bitmap mBitmap;
    //滑块对应的画笔
    private Paint mPaint;
    //滑块的宽度占比  高度自动对比
    private float mSlideWidthScale;
    //滑块的源图
    private Bitmap mResourseBitmap;
    //滑块图片
    private Bitmap mSlideBitmap;
    //滑块的宽度
    private int mSlide_width = 0;
    //滑块高度
    private int mSlide_height=0;
    //是否重新绘制图片
    private boolean isReset = true;
    //偏移值  最小2 最大100
    private int deviation;
    //阴影颜色
    private int shade_color= Color.GRAY;
    //阴影图片
    private Bitmap mShadeBitmap;
    //图片的最大宽度,最大高度
    private int max_width,max_height;
    //滑块移动距离
    private int mSlideMoveDistance =0;
    //随机生成的目标阴影xy初始坐标
    private int mShadeRandom_x,mShadeRandom_y;
    private OnSlideListener mListener;
    public interface OnSlideListener{
        void success();
        void error();

    }


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

    public SlideValidateView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SlideValidateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(R.styleable.SlideValidateView);
        max_width = ta.getDimensionPixelOffset(R.styleable.SlideValidateView_max_width,0);
        max_height = ta.getDimensionPixelOffset(R.styleable.SlideValidateView_max_height,0);
        Drawable drawable = ta.getDrawable(R.styleable.SlideValidateView_mSlideBitmap);
        mResourseBitmap = initResourseBitmap(drawable);
        shade_color = ta.getColor(R.styleable.SlideValidateView_shade_color, Color.GRAY);
        mSlideWidthScale = ta.getFloat(R.styleable.SlideValidateView_slideWidthScale,0.2f);
        deviation = ta.getInteger(R.styleable.SlideValidateView_deviation,10);
        ta.recycle();

        if(max_height==0||max_width==0){
            Point point = new Point();//x为宽,y为高
            ((Activity)context).getWindowManager().getDefaultDisplay().getSize(point);
            max_width = point.x;
            max_height =point.y/2;
        }
        if(deviation<2){
            deviation=2;
        }else if(deviation>100){
            deviation=100;
        }
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
    }


    public void setOnSlideListener(OnSlideListener listener){
        this.mListener = listener;
    }


    public void reset(){
        isReset = true;
        mSlideMoveDistance=0;
        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(isReset){
            mBitmap = getViewBitmap();
            if(mSlide_width==0&&mBitmap!=null&&mBitmap.getWidth()!=0){
                initSlideWH();
            }
            initSlideRandomXY();
            mShadeBitmap = Bitmap.createBitmap(mSlide_width,mSlide_height, Bitmap.Config.ARGB_8888);
            mShadeBitmap.eraseColor(shade_color);
            mSlideBitmap = Bitmap.createBitmap(mBitmap,mShadeRandom_x,mShadeRandom_y,mSlide_width,mSlide_height);

        }
        isReset = false;
        canvas.drawBitmap(drawImage(mShadeBitmap),mShadeRandom_x,mShadeRandom_y,mPaint);
        canvas.drawBitmap(drawImage(mSlideBitmap),mSlideMoveDistance,mShadeRandom_y,mPaint);

    }

    /***
     *
     * @param progress 1-100
     */
    public void setSlide_X(int progress){
        mSlideMoveDistance = (mBitmap.getWidth()-mSlide_width)/100*progress;
        if (mSlideMoveDistance > mBitmap.getWidth() - mSlide_width) {
            mSlideMoveDistance = mBitmap.getWidth() - mSlide_width;
        }
        postInvalidate();
    }

    /***
     * 检测
     */
    public void checkSlidePoint(){
        if( mListener !=null ){
            if (Math.abs(mSlideMoveDistance - mShadeRandom_x) <= deviation) {
                mListener.success();
            } else {
                mListener.error();
            }
        }

    }


    /****
     * 重构图片
     * @return
     */
    private Bitmap drawImage(Bitmap bitmap) {
        // 绘制图片
        Bitmap showB;
        if (null != mResourseBitmap) {
            showB = handleBitmap(mResourseBitmap, mSlide_width, mSlide_height);
        } else {
            showB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.star_shade), mSlide_width, mSlide_height);
        }
        Bitmap resultBmp = Bitmap.createBitmap(mSlide_width, mSlide_height, Bitmap.Config.ARGB_8888);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        Canvas canvas = new Canvas(resultBmp);
        canvas.drawBitmap(showB, new Rect(0, 0, mSlide_width, mSlide_height),
                new Rect(0, 0, mSlide_width, mSlide_height), paint);
        // 选择交集去上层图片
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        canvas.drawBitmap(bitmap, new Rect(0, 0, mSlide_width, mSlide_height),
                new Rect(0, 0, mSlide_width, mSlide_height), paint);
        return resultBmp;
    }
    /**
     * 缩放图片
     *
     * @param bp
     * @param x
     * @param y
     * @return
     */
    public static Bitmap handleBitmap(Bitmap bp, float x, float y) {
        int w = bp.getWidth();
        int h = bp.getHeight();
        float sx = (float) x / w;
        float sy = (float) y / h;
        Matrix matrix = new Matrix();
        matrix.postScale(sx, sy);
        Bitmap resizeBmp = Bitmap.createBitmap(bp, 0, 0, w,
                h, matrix, true);
        return resizeBmp;
    }
    /***
     * 初始化滑块的宽高
     */
    private void initSlideWH() {
        mSlide_width = (int) (mBitmap.getWidth()*mSlideWidthScale);
        float scale = ((float) mSlide_width)/mResourseBitmap.getWidth();
        mSlide_height = (int) (mResourseBitmap.getHeight()*scale);
    }

    /***
     * 初始化滑块起始位置
     */
    private void initSlideRandomXY() {
        mShadeRandom_x = (int) (mBitmap.getWidth()/2+(Math.random()*(mBitmap.getWidth()/2))-mSlide_width);
        mShadeRandom_y = (int) (Math.random() * (mBitmap.getHeight()-mSlide_height));
        if(mShadeRandom_x+mSlide_width>mBitmap.getWidth()||mShadeRandom_y+mSlide_height>mBitmap.getHeight()){
            initSlideRandomXY();
            return;
        }

    }

    private Bitmap initResourseBitmap(Drawable drawable){
        Bitmap bitmap;
        if(drawable ==null){
            bitmap = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.star_shade);
        }else {
            bitmap = drawable2bitmap(drawable);
        }
        return bitmap;

    }
    /***
     * drawable 转 bitmap
     * @param drawable
     * @return
     */
    private Bitmap drawable2bitmap(Drawable drawable){
        if(drawable==null){
            return null;
        }else if(drawable instanceof BitmapDrawable){
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }

    public Bitmap getViewBitmap() {
        Bitmap b = drawable2bitmap(getDrawable());
        float scaleX = 1.0f;
        float scaleY = 1.0f;
        // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;
        scaleX = getWidth() * 1.0f / b.getWidth();
        scaleY = getHeight() * 1.0f / b.getHeight();
        Matrix matrix = new Matrix();
        matrix.setScale(scaleX, scaleY);
        Bitmap bd = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                matrix, true);
        return bd;
    }
}

该原理参考于 该文章:https://blog.csdn.net/u013904672/article/details/51279520
对代码进行了部分优化 并设置了 seekbar只可拖动 不可点击。

拖动验证

这个就是一个捕获一个View的ontouch事件来自己处理。然后不断更改 margin值 没什么难点。
项目中的按钮大小是写死的 不然需延迟获取view.getwidth() 在onCreate中 获取为0 因为在这里该View并没有绘制完成

核心代码也就ontouch里的方法

img_start.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        start_x = img_start.getLeft();
                        start_y = img_start.getTop();
                        end_y = img_end.getTop();
                        lastX = event.getRawX();
                        lastY = event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //  不要直接用getX和getY,这两个获取的数据已经是经过处理的,容易出现图片抖动的情况
                        move_x = (int) (event.getRawX()-lastX);
                        move_y = (int) (event.getRawY()-lastY);
                        int distancex = start_x + move_x;
                        int distancey = start_y + move_y;
                        layoutParams.setMargins(distancex, distancey, 0, 0);
                        img_start.setLayoutParams(layoutParams);
                        if(distancex>end_x&&distancex<(end_x+img_end.getWidth())&&distancey>end_y&&distancey<(end_y+img_end.getHeight())){
                            Log.e("check","true");
                            if(!isCheck){
                                isCheck = true;
                                img_end.setImageResource(R.drawable.img_aty_verify_end_check);
                            }
                        }else if(isCheck){
                            Log.e("check","false");
                            isCheck = false;
                            img_end.setImageResource(R.drawable.img_aty_verify_end);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        if(isCheck){
                            img_start.setEnabled(false);
                            Toast.makeText(MainActivity.this,"success",Toast.LENGTH_SHORT).show();
                        }else {
                            img_end.setImageResource(R.drawable.img_aty_verify_end);
                            layoutParams.setMargins(start_x, start_y, 0, 0);
                            img_start.setLayoutParams(layoutParams);
                        }

                        break;
                }

                return true;
            }
        });

是不是很简单,只需要不断的更改params的margin就可以实现。

项目地址

该项目源码已上传至github

下载地址:点击前往Github

Over!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫的于

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值