Android仿支付宝手势密码二

接上篇Android仿支付宝手势密码一,本文实现随着手势的滑动,添加密码的行为。xml资源和完整代码在文末尾。

 

一 实现效果和分析

 

 

1.进入后随着手势的绘制完成 空心变为实心

2.绘制各个圆心的连接线

3.第二次绘制和第一次绘制做比较,如果绘制错误显示错误的圆

 

二 实现手势绘制完成空心变实心

思路:记录9个圆的位置,在手指滑动过程中,判断经过哪个圆并将其加入到经过的圆点集合当中。然后在for循环绘制9个圆过程中判断是绘制空心圆还是实心圆

每个圆心对应的位置如下,该位置就是以后保存的手势密码,比如012 表示手指先后经过了0 1 2三个点

2.1  画手指经过的圆

代码比较简单,就是在循环的时候,判断该点是否在手指经过的集合当中,如果在就画实心圆,不在就画空心圆

 

/**
 * 用于记录每个点的对应的位置坐标
 */
private HashMap<Integer, GesturePointBean> gesturePointMap = new HashMap<>();
    /**
     * 手指经过的点
     */
private List<Integer> pressPositionList = new ArrayList<>();

    private void init(Context context, AttributeSet attrs) {
        mContext = context;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GesturePwd);
        Drawable dw_selected = ta.getDrawable(R.styleable.GesturePwd_selectedDrawable);
        Drawable error_selected = ta.getDrawable(R.styleable.GesturePwd_selectedErrorDrawable);
        Drawable dw_unSeclect = ta.getDrawable(R.styleable.GesturePwd_unselectedDrawable);
        if (dw_selected != null) {
            selectedBitmap = BitmapUtils.drawableToBitmap(dw_selected);
        } else {
            selectedBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_blue_select));
        }


        if (dw_unSeclect != null) {
            unSelectedBitmap = BitmapUtils.drawableToBitmap(dw_unSeclect);
        } else {
            unSelectedBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_blue_unselect));
        }
        if (error_selected != null) {
            selectedErrorBitmap = BitmapUtils.drawableToBitmap(error_selected);
        } else {
            selectedErrorBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_red_select));
        }

        lastPointList.clear();
        pressPositionList.clear();
        pieceWidth = unSelectedBitmap.getWidth();
        //等待时间,默认30s
        waitTime = ta.getInteger(R.styleable.GesturePwd_waitTime, 800);
        pieceMargin = ta.getDimensionPixelOffset(R.styleable.GesturePwd_pieceMargin, 100);
        Log.d(TAG, "init: pieceMargin==" + pieceMargin);
        //最小设置的点,默认4个
        minPointNums = ta.getInteger(R.styleable.GesturePwd_minPoint, 4);
        maxPointNums = ta.getInteger(R.styleable.GesturePwd_maxPoint, 10);
        mPaint = new Paint();
        mPaint.setStrokeWidth(5);

        //画笔的颜色
        pathColor = ta.getColor(R.styleable.GesturePwd_pathColor, context.getResources().getColor(R.color.Blue56));
        mPaint.setColor(pathColor);
        mPath = new Path();
        //避免重新创建时候的错误
        ta.recycle();

    }
 
 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.canvas = canvas;
        gesturePointMap.clear();
        //画大view
        int key = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                float x;
                float y;
                if (j == 0) {
                    x = (float) (getWidth() / 2 - 1.5 * pieceWidth - pieceMargin);
                } else {
                    x = (float) (getWidth() / 2 - 1.5 * pieceWidth - pieceMargin + j * pieceWidth + pieceMargin * j);
                }
                y = (float) (i * pieceWidth + i * pieceMargin);
                GesturePointBean gestureBean = new GesturePointBean((int) x, (int) y);
                gesturePointMap.put(key, gestureBean);
                drawCircle(key, x, y, canvas);
                key++;
            }
        }

 //drawPath();
    }

    private void drawCircle(int k, float x, float y, Canvas canvas) {
        boolean findSelect = false;
        if (pressPositionList != null && pressPositionList.size() > 0) {
            for (Integer integer : pressPositionList) {
                if (integer == k) {
                    findSelect = true;
                }
            }
        }
        if (findSelect) {
            canvas.drawBitmap(selectedBitmap, x, y, mPaint);
        } else {
            canvas.drawBitmap(unSelectedBitmap, x, y, mPaint);
        }
    }

2.2  绘制手指经过的点

judgeClickPosition函数根据手指在屏幕上的xy坐标,确定经过的点。其原理也比较简单就是每个点对应的坐标值,如果手指在该范围内,就表示经过了该点

onTouchEvent函数,
actiondonw: 在手指按下的时候,将手指经过的点集合清空,然后再将该点添加进集合当中,注意这时需要return true,否则后面的move和up收不到滑动事件。
action_move: 随着手指的滑动,判断滑动的点是否和上一个点一样,如果不一样添加进集合。如果超过了规定的最大连接圆个数不添加。注意这里做了一个容错处理,为什么要这么做呢?大家可以试试从位置0 到位置2 ,如果手指绕过了1,那么添加进集合的就是0 2,最后画出来的圆就是0 2 变为实心,但是1没有,显然这样不合理。
action_up:手指抬起,如果小于规定最小圆个数清空选中的圆心集合。

 

     private int lastPosition;//上一次点击的点
    private int curPosition;//当前点
    private boolean actionUp;
    //当前手指的坐标
    private float currY;
    private float currX;
    /**
     * 用于标识 两次画的连接线是否一样  如果一样第二次画的时候默认正确颜色 否则错误颜色
     * 默认都是一样 即绘制正确颜色
     */
    private boolean verfiy;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        currX = event.getX();
        currY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                if (judgeClickPosition(event.getX(), event.getY()) != -1) {
                    pressPositionList.clear();
                    curPosition = judgeClickPosition(event.getX(), event.getY());
                    pressPositionList.add(curPosition);
                    lastPosition = curPosition;
                    actionUp = false;
                    invalidate();

                }
                verfiy = true;
                return true;

            case MotionEvent.ACTION_MOVE:
                //手指从一个点移动到了另一个点

                curPosition = judgeClickPosition(event.getX(), event.getY());
                if (curPosition != -1 && curPosition != lastPosition) {
                    if (pressPositionList.size() <= maxPointNums) {
                        //做一下容错处理 比如手指在0 到6 中间 手指绕过了3 显然不合理
                        //容错处理的线是 0 2, 0 6 ,1 7 ,2 6 ,2 8,3 5
                        if((lastPosition==0&&curPosition==2)||(lastPosition==2&&curPosition==0)){
                            pressPositionList.add(1);
                        }
                        if((lastPosition==0&&curPosition==6)||(lastPosition==6&&curPosition==0)){
                            pressPositionList.add(3);
                        }
                        if((lastPosition==0&&curPosition==8)||(lastPosition==8&&curPosition==0)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==1&&curPosition==7)||(lastPosition==7&&curPosition==1)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==2&&curPosition==6)||(lastPosition==6&&curPosition==2)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==2&&curPosition==8)||(lastPosition==8&&curPosition==2)){
                            pressPositionList.add(5);
                        }
                        if((lastPosition==3&&curPosition==5)||(lastPosition==5&&curPosition==3)){
                            pressPositionList.add(4);
                        }

                        if((lastPosition==6&&curPosition==8)||(lastPosition==8&&curPosition==6)){
                            pressPositionList.add(7);
                        }
                        pressPositionList.add(curPosition);
                        Log.d(TAG, "onTouchEvent: 添加了:" + curPosition);
                        lastPosition = curPosition;
                    } else {
                        //大于最大连接个数 不添加
//                        if (onChoosePointListener != null) {
//                            onChoosePointListener.onError("最多连接"+maxPointNums+"个点");
//                        }
                    }

                }
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                actionUp = true;
                if (pressPositionList.size() < minPointNums) {
                    //小于最小连接个数 将选中的点清空
                    pressPositionList.clear();
                    invalidate();
                } else {
                    //绘制正确 进入验证逻辑
//                    registerDraw();
                }

                break;
        }

        return super.onTouchEvent(event);
    }



  /**
     * 计算点击位置
     *
     * @param x
     * @param y
     * @return
     */
    private int judgeClickPosition(float x, float y) {
        int position = -1;
        if (y < pieceWidth) {
            //点击第一行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 0;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 1;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 2;
            }

        } else if (y >= pieceWidth + pieceMargin && y < 2 * pieceWidth + pieceMargin) {
            //点击第二行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 3;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 4;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 5;
            }
        } else if (y >= 2 * pieceWidth + 2 * pieceMargin) {
            //点击第三行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 6;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 7;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 8;
            }
        }
        return position;
    }

这个时候已经可以实现如下效果了:

大家思考下,这时是不是还没有实现如果绘制的手势和上一次不一样显示红色错误的状态呢,如何来实现呢?

其实,思路和绘制实心圆一样,就是再手指抬起的时候,在ondraw绘制的过程当中,判断是否和上一次经过的圆点一样,如果不一样就绘制错误的红心圆


    /**
     * 注册绘制
     */
    private void registerDraw() {
        if (lastPointList.size() == 0) {
            //第一次绘制 回调绘制完成并清空图案
            lastPointList.addAll(pressPositionList);

            clearPointInValidate();
        } else {
            //和第一次绘制图案相比较
            comparePoint();
        }
    }

    /**
     * 过一秒清空图案
     */
    private void clearPointInValidate() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(waitTime);//休眠2秒
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                pressPositionList.clear();
                postInvalidate();
            }
        }.start();
    }

    private void comparePoint() {
        String lastPoint = "";
        String curPoint = "";
        for (Integer integer : lastPointList) {
            lastPoint = lastPoint + integer;
        }
        for (Integer integer : pressPositionList) {
            curPoint = curPoint + integer;
        }
        if (lastPoint.equals(curPoint)) {
            //两次输入手势一样

        } else {
            //两次不一样
            verfiy = false;
            clearPointInValidate();
        }
        invalidate();
    }
 

private void drawCircle(int k, float x, float y, Canvas canvas) {
        boolean findSelect = false;
        if (pressPositionList != null && pressPositionList.size() > 0) {
            for (Integer integer : pressPositionList) {
                if (integer == k) {
                    findSelect = true;

                }
            }
        }
        if (findSelect) {
            if (verfiy) {
                canvas.drawBitmap(selectedBitmap, x, y, mPaint);
            } else {
                canvas.drawBitmap(selectedErrorBitmap, x, y, mPaint);
            }
        } else {
            canvas.drawBitmap(unSelectedBitmap, x, y, mPaint);
        }
    }

大家将ontouch--->action_up当中的绘制正确的注释代码放开,绘制正确的时候将手指经过的点和上一次经过的相比较,如果不一样就做出一个错误标识,从而在绘制圆心的时候绘制错误圆。注意这过程当中有两次invalidate,第一次是手指抬起就通知系统绘制,第二次是判断手势是否正确再通知等待规定时间再通知绘制,此时效果

 

三 绘制经过的直线路径

效果

可以分为两步骤

1.绘制手势经过圆心的连接线

2.手指在移动过程当中绘制最后一个圆到手指在屏幕上面的坐标

 

  /**
     * 画连接线
     */
    private void drawPath() {

        mPath.reset();
        mPaint.setStyle(Paint.Style.STROKE);
        if (pressPositionList == null || pressPositionList.size() == 0) {
            return;
        }

        for (int i = 0; i < pressPositionList.size(); i++) {
            GesturePointBean gesturePointBean = gesturePointMap.get(pressPositionList.get(i));
            if (gesturePointBean != null) {
                if (i == 0) {
                    mPath.moveTo(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2);
                }
                mPath.lineTo(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2);
            }
        }
        canvas.drawPath(mPath, mPaint);

        //画最后一根线
        if (!actionUp) {
            GesturePointBean gesturePointBean = gesturePointMap.get(pressPositionList.get(pressPositionList.size() - 1));
            canvas.drawLine(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2, currX, currY, mPaint);
        }


    }

大家可以把ondraw里面的drawPath注释去掉查看效果

四 优化和整体代码

手势的应用场景是两个 :

1.注册,和上一次手势比较错误,画红心圆

2.登录 ,和传入的手势密码(012位置格式)比较错误画红心圆

注册上述已经实现了,登录的原理和注册一样,只是比较的手势改成了传入的手势密码。

除此之外,还应该给该自定义view添加监听,绘制完成的手势密码,绘制错误等。基本都是逻辑代码,就不详细介绍了

 

/**
 * 创建日期:2021/3/17 9:35
 *
 * @author LuoJ
 * @version 1.0
 * 包名: com.example.learn.home.customview.view
 * 类说明:
 */
public class GesturePwdView extends View {
    private Context mContext;
    /**
     * 圆点图片
     */
    private Bitmap selectedBitmap;
    private Bitmap selectedErrorBitmap;
    private Bitmap unSelectedBitmap;
    //绘制第二次手势的等待时间
    private int waitTime;

    private int minPointNums;//最小连接个数
    private int maxPointNums;//最大连接个数
    private Paint mPaint;
    /**
     * 连接线颜色
     */
    private int pathColor;
    /**
     * 绘制错误的连接线颜色
     */
    private int errorPathColor;

    private int pieceWidth;//每个大view圆点宽度
    private int pieceMargin;//每个圆间隔的距离

    /**
     * 用于记录每个点的对应的位置坐标
     */
    private HashMap<Integer, GesturePointBean> gesturePointMap = new HashMap<>();

    /**
     * 手指经过的点
     */
    private List<Integer> pressPositionList = new ArrayList<>();
    /**
     * 用于记录上一次的点
     */
    private List<Integer> lastPointList = new ArrayList<>();
    private String TAG = "GesturePwdView";
    private Path mPath;
    private Canvas canvas;
    /**
     * 用于标识 两次画的连接线是否一样  如果一样第二次画的时候默认正确颜色 否则错误颜色
     * 默认都是一样 即绘制正确颜色
     */
    private boolean verfiy;
    private String gesturePwd;
    /**
     * 默认是注册
     */
    private boolean state_login = false;
    /**
     * 记录登录时候的绘制次数
     */
    private int drawLoginCount;

    public GesturePwdView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public GesturePwdView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }


    private void init(Context context, AttributeSet attrs) {
        mContext = context;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GesturePwd);
        Drawable dw_selected = ta.getDrawable(R.styleable.GesturePwd_selectedDrawable);
        Drawable error_selected = ta.getDrawable(R.styleable.GesturePwd_selectedErrorDrawable);
        Drawable dw_unSeclect = ta.getDrawable(R.styleable.GesturePwd_unselectedDrawable);
        if (dw_selected != null) {
            selectedBitmap = BitmapUtils.drawableToBitmap(dw_selected);
        } else {
            selectedBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_blue_select));
        }

        if (error_selected != null) {
            selectedErrorBitmap = BitmapUtils.drawableToBitmap(error_selected);
        } else {
            selectedErrorBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_red_select));
        }


        if (dw_unSeclect != null) {
            unSelectedBitmap = BitmapUtils.drawableToBitmap(dw_unSeclect);
        } else {
            unSelectedBitmap = BitmapUtils.drawableToBitmap(getResources().getDrawable(R.drawable.circle_blue_unselect));
        }
        lastPointList.clear();
        pressPositionList.clear();
        pieceWidth = unSelectedBitmap.getWidth();
        //等待时间,默认30s
        waitTime = ta.getInteger(R.styleable.GesturePwd_waitTime, 800);
        pieceMargin = ta.getDimensionPixelOffset(R.styleable.GesturePwd_pieceMargin, 100);
        Log.d(TAG, "init: pieceMargin==" + pieceMargin);
        //最小设置的点,默认4个
        minPointNums = ta.getInteger(R.styleable.GesturePwd_minPoint, 4);
        maxPointNums = ta.getInteger(R.styleable.GesturePwd_maxPoint, 10);
        mPaint = new Paint();
        mPaint.setStrokeWidth(5);

        //画笔的颜色
        pathColor = ta.getColor(R.styleable.GesturePwd_pathColor, context.getResources().getColor(R.color.Blue56));
        errorPathColor = ta.getColor(R.styleable.GesturePwd_errorPathColor, context.getResources().getColor(R.color.read_f9));
        mPaint.setColor(pathColor);
        mPath = new Path();
        //避免重新创建时候的错误
        ta.recycle();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? measureWidth : pieceMargin * 2 + pieceWidth * 3, (measureHeightMode == MeasureSpec.EXACTLY) ? measureHeight : pieceMargin * 2 + pieceWidth * 3);
//        setMeasuredDimension( pieceMargin * 2 + pieceWidth * 3, (measureHeightMode == MeasureSpec.EXACTLY) ? measureHeight : pieceMargin * 2 + pieceWidth * 3);

    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.canvas = canvas;
        gesturePointMap.clear();
        //画大view
        int key = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                float x;
                float y;
                if (j == 0) {
                    x = (float) (getWidth() / 2 - 1.5 * pieceWidth - pieceMargin);
                } else {
                    x = (float) (getWidth() / 2 - 1.5 * pieceWidth - pieceMargin + j * pieceWidth + pieceMargin * j);
                }
                y = (float) (i * pieceWidth + i * pieceMargin);
                GesturePointBean gestureBean = new GesturePointBean((int) x, (int) y);
                gesturePointMap.put(key, gestureBean);
                drawCircle(key, x, y, canvas);
                key++;
            }
        }

        drawPath();

    }

    /**
     * 画连接线
     */
    private void drawPath() {
        if (verfiy) {
            mPaint.setColor(pathColor);

        } else {
            mPaint.setColor(errorPathColor);
        }
        mPath.reset();
        mPaint.setStyle(Paint.Style.STROKE);
        if (pressPositionList == null || pressPositionList.size() == 0) {
            return;
        }

        for (int i = 0; i < pressPositionList.size(); i++) {
            GesturePointBean gesturePointBean = gesturePointMap.get(pressPositionList.get(i));
            if (gesturePointBean != null) {
                if (i == 0) {
                    mPath.moveTo(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2);
                }
                mPath.lineTo(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2);
            }
        }
        canvas.drawPath(mPath, mPaint);

        //画最后一根线
        if (!actionUp) {
            GesturePointBean gesturePointBean = gesturePointMap.get(pressPositionList.get(pressPositionList.size() - 1));
            canvas.drawLine(gesturePointBean.getX() + pieceWidth / 2, gesturePointBean.getY() + pieceWidth / 2, currX, currY, mPaint);
        }


    }

    //当前手指的坐标
    private float currY;
    private float currX;


    private int lastPosition;//上一次点击的点
    private int curPosition;//当前点
    private boolean actionUp;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        currX = event.getX();
        currY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                if (judgeClickPosition(event.getX(), event.getY()) != -1) {
                    pressPositionList.clear();
                    curPosition = judgeClickPosition(event.getX(), event.getY());
                    pressPositionList.add(curPosition);
                    lastPosition = curPosition;
                    actionUp = false;
                    invalidate();

                }
                verfiy = true;
                return true;

            case MotionEvent.ACTION_MOVE:
                //手指从一个点移动到了另一个点

                curPosition = judgeClickPosition(event.getX(), event.getY());
                if (curPosition != -1 && curPosition != lastPosition) {

                    if (pressPositionList.size() <= maxPointNums) {
                        //做一下容错处理 比如手指在0 到6 中间 手指绕过了3 显然不合理
                        //容错处理的线是 0 2, 0 6 ,1 7 ,2 6 ,2 8,3 5
                        if((lastPosition==0&&curPosition==2)||(lastPosition==2&&curPosition==0)){
                            pressPositionList.add(1);
                        }
                        if((lastPosition==0&&curPosition==6)||(lastPosition==6&&curPosition==0)){
                            pressPositionList.add(3);
                        }
                        if((lastPosition==0&&curPosition==8)||(lastPosition==8&&curPosition==0)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==1&&curPosition==7)||(lastPosition==7&&curPosition==1)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==2&&curPosition==6)||(lastPosition==6&&curPosition==2)){
                            pressPositionList.add(4);
                        }
                        if((lastPosition==2&&curPosition==8)||(lastPosition==8&&curPosition==2)){
                            pressPositionList.add(5);
                        }
                        if((lastPosition==3&&curPosition==5)||(lastPosition==5&&curPosition==3)){
                            pressPositionList.add(4);
                        }

                        if((lastPosition==6&&curPosition==8)||(lastPosition==8&&curPosition==6)){
                            pressPositionList.add(7);
                        }
                        pressPositionList.add(curPosition);
                        Log.d(TAG, "onTouchEvent: 添加了:" + curPosition);
                        lastPosition = curPosition;
                    } else {
                        //大于最大连接个数 不添加
//                        if (onChoosePointListener != null) {
//                            onChoosePointListener.onError("最多连接"+maxPointNums+"个点");
//                        }
                    }

                }
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                actionUp = true;
                if (pressPositionList.size() < minPointNums) {
                    //小于最小连接个数 将选中的点清空
                    pressPositionList.clear();
                    if (onChoosePointListener != null) {
                        onChoosePointListener.onError("最少连接" + minPointNums + "个点,请重新输入");
                    }
                    invalidate();
                } else {
                    //绘制正确 进入验证逻辑
                    if (state_login) {
                        //登录
                        loginDraw();
                    } else {
                        registerDraw();
                    }
                }

                break;
        }

        return super.onTouchEvent(event);
    }

    private void loginDraw() {
        String curPoint = "";
        for (Integer integer : pressPositionList) {
            curPoint = curPoint + integer;
        }
        int success = 0;
        if (curPoint.equals(gesturePwd)) {
            //绘制 正确
            success = 1;

        } else {
            //绘制错误
            drawLoginCount++;
            verfiy = false;
            clearPointInValidate();
        }
        if (onChoosePointListener != null) {
            onChoosePointListener.onLogin(success, drawLoginCount);
        }
        invalidate();
    }

    /**
     * 注册绘制
     */
    private void registerDraw() {
        if (lastPointList.size() == 0) {
            //第一次绘制 回调绘制完成并清空图案
            lastPointList.addAll(pressPositionList);
            if (onChoosePointListener != null) {
                onChoosePointListener.onDrawFirstFinish(pressPositionList);
            }
            clearPointInValidate();
        } else {
            //和第一次绘制图案相比较
            comparePoint();
        }
    }

    /**
     * 过一秒清空图案
     */
    private void clearPointInValidate() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(waitTime);//休眠2秒
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                pressPositionList.clear();
                postInvalidate();
            }
        }.start();
    }

    private void comparePoint() {
        String lastPoint = "";
        String curPoint = "";
        for (Integer integer : lastPointList) {
            lastPoint = lastPoint + integer;
        }
        for (Integer integer : pressPositionList) {
            curPoint = curPoint + integer;
        }
        if (lastPoint.equals(curPoint)) {
            //两次输入手势一样
            if (onChoosePointListener != null) {
                onChoosePointListener.onVirfiyFinish(curPoint);
            }
        } else {
            //两次不一样
            verfiy = false;
            if (onChoosePointListener != null) {
                onChoosePointListener.onError("与上次绘制不一致,请重新绘制");
            }
            clearPointInValidate();
        }
        invalidate();
    }

    /**
     * 计算点击位置
     *
     * @param x
     * @param y
     * @return
     */
    private int judgeClickPosition(float x, float y) {
        int position = -1;
//        if (x >= getWidth() / 2 - pieceWidth * 1.5 - pieceMargin && x <= getWidth() / 2 + pieceWidth * 1.5 + pieceMargin) {
        if (y < pieceWidth) {
            //点击第一行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 0;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 1;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 2;
            }

        } else if (y >= pieceWidth + pieceMargin && y < 2 * pieceWidth + pieceMargin) {
            //点击第二行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 3;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 4;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 5;
            }
        } else if (y >= 2 * pieceWidth + 2 * pieceMargin) {
            //点击第三行
            if (x < getWidth() / 2 - 0.5 * pieceWidth - pieceMargin) {
                position = 6;
            } else if (x >= getWidth() / 2 - 0.5 * pieceWidth && x < getWidth() / 2 + 0.5 * pieceWidth) {
                position = 7;
            } else if (x >= getWidth() / 2 + 0.5 * pieceWidth + pieceMargin) {
                position = 8;
            }
        }
//        }
        return position;
    }

    /**
     * 画园的时候判断是否有点击的圆
     *
     * @param k
     * @param x
     * @param y
     * @param canvas
     */
    private void drawCircle(int k, float x, float y, Canvas canvas) {
        boolean findSelect = false;
        if (pressPositionList != null && pressPositionList.size() > 0) {
            for (Integer integer : pressPositionList) {
                if (integer == k) {
                    findSelect = true;

                }
            }
        }
        if (findSelect) {
            if (verfiy) {
                canvas.drawBitmap(selectedBitmap, x, y, mPaint);

            } else {
                canvas.drawBitmap(selectedErrorBitmap, x, y, mPaint);
            }

        } else {
            canvas.drawBitmap(unSelectedBitmap, x, y, mPaint);
        }
    }

    public interface OnChoosePointListener {

        /**
         * 绘制完成
         *
         * @param positions
         */
        void onDrawFirstFinish(List<Integer> positions);

        /**
         * 绘制错误
         *
         * @param text
         */
        void onError(String text);

        void onVirfiyFinish(String pwd);


        /**
         * @param type      0 登录失败  1登录成功
         * @param drawCount 绘制次数
         */
        void onLogin(int type, int drawCount);
    }

    private OnChoosePointListener onChoosePointListener;

    public void setOnChoosePointListener(OnChoosePointListener onChoosePointListener) {
        this.onChoosePointListener = onChoosePointListener;
    }

    public void setGesturePwd(String gesturePwd) {
        this.gesturePwd = gesturePwd;
        if (gesturePwd != null && !gesturePwd.equals("")) {
            state_login = true;
        }

        pressPositionList.clear();
        lastPointList.clear();
        invalidate();
    }
}

 

错误圆心xml代码

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="oval">
            <size
                android:width="50dp"
                android:height="50dp" />
            <solid android:color="@color/read_f9" />
        </shape>
    </item>

    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="oval">
            <solid android:color="@color/white" />
        </shape>
    </item>
    <item
        android:bottom="16dp"
        android:left="16dp"
        android:right="16dp"
        android:top="16dp">
        <shape android:shape="oval">
            <solid android:color="@color/read_f9" />
        </shape>
    </item>

</layer-list>

选中圆心代码

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="oval">
            <size
                android:width="50dp"
                android:height="50dp" />
            <solid android:color="@color/Blue56" />
        </shape>
    </item>

    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="oval">
            <solid android:color="@color/white" />
        </shape>
    </item>
    <item
        android:bottom="16dp"
        android:left="16dp"
        android:right="16dp"
        android:top="16dp">
        <shape android:shape="oval">
            <solid android:color="@color/Blue56" />
        </shape>
    </item>

</layer-list>

颜色代码:

    <color name="Blue56">#5677fc</color>
    <color name="read_f9">#F95252</color>

接下来将实现手势密码注册的上半部分view并列举实际应用 Android仿支付宝手势密码三

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值