精华内容
下载资源
问答
  • 完美图案解锁

    2014-09-10 16:40:35
    完整的一套图案解锁程序,类似支付宝的图案解锁,有加密
  • 图案解锁

    2019-01-20 19:11:28
    图案解锁实现步骤 1.自定义一个View package com.example.administrator.mydemo.graphiclock; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import ...

    图案解锁实现步骤
    1.自定义一个View

    package com.example.administrator.mydemo.graphiclock;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.os.Handler;
    import android.os.Message;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    
    import com.example.administrator.mydemo.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by Jack on 16/10/12.
     */
    public class GraphicLockView extends View {
    
        private Point[][] points = new Point[3][3];  //创建一个3行3列的点数组
    
        private boolean isInit;   //判断有没有初始化
    
        private boolean isSelect;  //判断手指第一次按下屏幕有没有选中点
    
        private boolean isFinishMove;   //表示一次完整的图案绘制是否结束
    
        private boolean isMoveButNotPoint;   //表示手指在移动,但是并不是九宫格中的点
    
        private float width, height;   //屏幕宽高
    
        private static final int MIN_POINT = 4;    //最小能构成密码的点数
    
        private float offsetsX, offsetsY; //偏移量(在这里偏移量等于大边减去小边再除以2)
    
        private float bitmapR;   //图片资源的半径
    
        private float moveX, moveY;  //手势移动的x,y坐标
    
        private Bitmap bpPointNormal, bpPointPressed, bpPointError;  //点的三种图片
    
        private Bitmap bpLinePressed, bpLineError;  //线的三种图片
    
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
        private List<Point> selectPointList = new ArrayList<>();   //储存按下的点的集合
    
        private Matrix matrix = new Matrix();  //矩阵,用来处理线的缩放
    
        private OnGraphicLockListener onGraphicLockListener;   //对外的监听器
    
        public GraphicLockView(Context context) {
            super(context);
        }
    
        public GraphicLockView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public GraphicLockView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public void setOnGraphicLockListener(OnGraphicLockListener onGraphicLockListener) {
            this.onGraphicLockListener = onGraphicLockListener;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //绘制之前要先初始化一下点,所以要先判断有没有初始化过
            if (!isInit) {
                //初始化点
                initPoints();
            }
            //绘制——将点绘制到画布上
            pointToCanvas(canvas);
    
            if (selectPointList.size() > 0) {
                Point startPoint = selectPointList.get(0);
                //绘制九宫格坐标里的点
                for (int i = 0; i < selectPointList.size(); i++) {
                    Point endPoint = selectPointList.get(i);
                    lineToCanvas(canvas, startPoint, endPoint);
                    startPoint = endPoint;
                }
                //绘制九宫格坐标以外的点
                if (isMoveButNotPoint) {
                    lineToCanvas(canvas, startPoint, new Point(moveX, moveY));
                }
            }
        }
    
        /**
         * 初始化点
         */
        private void initPoints() {
            //1、先拿到画布的宽高(屏幕的宽高)
            width = getWidth();
            height = getHeight();
    
            /*================================================================================*/
    
            //2、判断横竖屏并且计算偏移量
            if (width > height) {   //横屏
                //横屏时只有x坐标有偏移量
                offsetsX = (width - height) / 2;
                /**
                 * 将手机屏幕可以看作是一个正方形(因为九宫格是正方形,在这里比较好计算),以最小边为基准
                 */
                width = height;
            } else {   //竖屏
                //竖屏时只有y坐标有偏移量
                offsetsY = ((height - width) / 3);
                height = width;
            }
    
            /*================================================================================*/
    
            //3、图片资源(图片资源自己加上)
            bpPointNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);//默认图片
            bpPointPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);//选中图片
            bpPointError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);//报红提示图片
            bpLinePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);//连接线图片
            bpLineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);//报红连接线
    
            /*================================================================================*/
    
            //4、点的坐标
            //第一排
            points[0][0] = new Point(offsetsX + width / 4, offsetsY + height / 4);
            points[0][1] = new Point(offsetsX + width / 2, offsetsY + height / 4);
            points[0][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 4);
    
            //第二排
            points[1][0] = new Point(offsetsX + width / 4, offsetsY + height / 2);
            points[1][1] = new Point(offsetsX + width / 2, offsetsY + height / 2);
            points[1][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 2);
    
            //第三排
            points[2][0] = new Point(offsetsX + width / 4, offsetsY + height - height / 4);
            points[2][1] = new Point(offsetsX + width / 2, offsetsY + height - height / 4);
            points[2][2] = new Point(offsetsX + width - width / 4, offsetsY + height - height / 4);
    
    
            /*================================================================================*/
    
            //5、计算图片资源的半径
            bitmapR = bpPointNormal.getWidth() / 2;
    
            /*================================================================================*/
    
            //6、设置密码按键,初始化每个点,设置为1——9
            int index = 1;
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[i].length; j++) {
                    points[i][j].index = index;
                    index++;
                }
            }
            /*================================================================================*/
    
            //初始化完成
            isInit = true;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            moveX = event.getX();
            moveY = event.getY();
            isFinishMove = false;
            isMoveButNotPoint = false;
            Point point = null;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //每次手指按下的时候都表示重新绘制图案
                    resetPoint();
                    //1、检查当前按下的点与九宫格中的九个点是否吻合
                    point = checkSelectPoint();
                    if (point != null) {
                        isSelect = true;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (isSelect) {
                        point = checkSelectPoint();
                        if (point == null) {
                            isMoveButNotPoint = true;
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    isFinishMove = true;
                    isSelect = false;
                    break;
            }
            //选中重复检查
            if (!isFinishMove && isSelect && point != null) {
                if (checkCrossPoint(point)) {  //交叉点
                    isMoveButNotPoint = true;
                } else {   //非交叉点(新的点)
                    point.status = Point.STATE_PRESSED;
                    selectPointList.add(point);
                }
            }
            //绘制结束
            if (isFinishMove) {
                //绘制不成立
                if (selectPointList.size() == 1) {
                    resetPoint();
                    //绘制错误,点不够
                } else if (selectPointList.size() < MIN_POINT && selectPointList.size() > 0) {
                    if (null != onGraphicLockListener) {
                        onGraphicLockListener.setPwdFailure();
                    }
                    errorPoint();
                    //绘制成功
                } else {
                    if (null != onGraphicLockListener) {
                        String strPassword = "";
                        for (Point pwdPoint : selectPointList) {
                            strPassword += pwdPoint.index;
                        }
                        if (!TextUtils.isEmpty(strPassword)) {
                            onGraphicLockListener.setPwdSuccess(strPassword);
                        }
                        correctPoint();
                    }
                }
            }
            //刷新view,会调用onDraw方法
            postInvalidate();
            return true;
        }
    
        /**
         * 检查交叉点
         *
         * @param point 点
         * @return 是否交叉
         */
        private boolean checkCrossPoint(Point point) {
            if (selectPointList.contains(point)) {
                return true;
            }
            return false;
        }
    
        /**
         * 设置绘制不成立
         */
        public void resetPoint() {
            //将点的状态还原
            for (Point point : selectPointList) {
                point.status = Point.STATE_NORMAL;
            }
            selectPointList.clear();
        }
    
        /**
         * 设置绘制错误,将点的状态还原
         */
        public void errorPoint() {
            for (Point point : selectPointList) {
                point.status = Point.STATE_ERROR;
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    handler.sendEmptyMessage(0);
                }
            }).start();
        }
    
        /**
         * 设置绘制成功,将点的状态还原
         */
        private void correctPoint() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    handler.sendEmptyMessage(0);
                }
            }).start();
        }
    
        @SuppressLint("HandlerLeak")
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                for (Point point : selectPointList) {
                    point.status = Point.STATE_NORMAL;
                }
                selectPointList.clear();
                postInvalidate();
            }
        };
    
        private Point checkSelectPoint() {
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[i].length; j++) {
                    Point point = points[i][j];
                    if (AppUtil.isCoincide(point.x, point.y, bitmapR, moveX, moveY)) {
                        return point;
                    }
                }
            }
            return null;
        }
    
        /**
         * 将点绘制到画布上
         *
         * @param canvas 画布
         */
        private void pointToCanvas(Canvas canvas) {
            //遍历点的集合
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[i].length; j++) {
                    Point point = points[i][j];
                    if (points[i][j].status == Point.STATE_PRESSED) {
                        canvas.drawBitmap(bpPointPressed, point.x - bitmapR, point.y - bitmapR, mPaint);
                    } else if (points[i][j].status == Point.STATE_ERROR) {
                        canvas.drawBitmap(bpPointError, point.x - bitmapR, point.y - bitmapR, mPaint);
                    } else {
                        canvas.drawBitmap(bpPointNormal, point.x - bitmapR, point.y - bitmapR, mPaint);
                    }
                }
            }
        }
    
        /**
         * 将线绘制到画布上
         *
         * @param canvas     画布
         * @param startPoint 开始的点
         * @param endPoint   结束的点
         */
        private void lineToCanvas(Canvas canvas, Point startPoint, Point endPoint) {
            float lineLength = (float) AppUtil.twoPointDistance(startPoint, endPoint);
            float degree = AppUtil.getDegrees(startPoint, endPoint);
            canvas.rotate(degree, startPoint.x, startPoint.y);  //旋转
            if (startPoint.status == Point.STATE_PRESSED) {  //按下的状态
                //设置线的缩放比例,在这里线是往一个方向缩放的,即x轴,我们只需要设置x轴的缩放比例即可,y轴默认为1
                matrix.setScale(lineLength / bpLinePressed.getWidth(), (float) 0.2);
                matrix.postTranslate(startPoint.x - bpLinePressed.getWidth() / 8, startPoint.y - bpLinePressed.getHeight() / 8);
                canvas.drawBitmap(bpLinePressed, matrix, mPaint);
            } else {   //错误的状态
                matrix.setScale(lineLength / bpLineError.getWidth(), (float) 0.2);
                matrix.postTranslate(startPoint.x - bpLineError.getWidth() / 8, startPoint.y - bpLineError.getHeight() / 8);
                canvas.drawBitmap(bpLineError, matrix, mPaint);
            }
            canvas.rotate(-degree, startPoint.x, startPoint.y);  //把旋转的角度转回来
        }
    
        /**
         * 图案监听器
         */
        public interface OnGraphicLockListener {
            void setPwdSuccess(String password);
    
            void setPwdFailure();
        }
    }
    
    

    2.绘制点工具类

    package com.example.administrator.mydemo.graphiclock;
    
    /**
     * 自定义的Point
     * Created by Jack on 16/10/12.
     */
    public class Point {
    
        //正常状态
        public static int STATE_NORMAL = 0;
        //选中状态
        public static int STATE_PRESSED = 1;
        //错误状态
        public static int STATE_ERROR = 2;
    
        public float x, y;
    
        public int index = 0, status = 0;
    
        public Point() {
    
        }
    
        public Point(float x, float y) {
            this.x = x;
            this.y = y;
        }
    }
    

    3.滑动工具类

    package com.example.administrator.mydemo.graphiclock;
    
    /**
     * Created by Jack on 16/10/12.
     */
    public class AppUtil {
        /**
         * 两点之间的距离
         *
         * @param a 第一个点
         * @param b 第二个点
         * @return 距离
         */
        public static double twoPointDistance(Point a, Point b) {
            //x轴差的平方加上y轴的平方,然后取平方根
            return Math.sqrt(Math.abs(a.x - b.x) * Math.abs(a.x - b.x) + Math.abs(a.y - b.y) * Math.abs(a.y - b.y));
        }
    
        /**
         * 判断手指移动的坐标与点的坐标是否重合(默认小于点半径的一半的时候表示重合)
         *
         * @param pointX 点横坐标
         * @param pointY 点纵坐标
         * @param r      点半径
         * @param moveX  手指移动的横坐标
         * @param moveY  手指移动的纵坐标
         * @return
         */
        public static boolean isCoincide(float pointX, float pointY, float r, float moveX, float moveY) {
            return Math.sqrt((pointX - moveX) * (pointX - moveX) + (pointY - moveY) * (pointY - moveY)) < r;
        }
    
        /**
         * 获取角度
         *
         * @param pointA 第一个点
         * @param pointB 第二个点
         * @return
         */
        public static float getDegrees(Point pointA, Point pointB) {
            return (float) Math.toDegrees(Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x));
        }
    }
    
    

    4.调用逻辑

    package com.example.administrator.mydemo.graphiclock;
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.example.administrator.mydemo.R;
    
    
    public class GraphicLockActivity extends AppCompatActivity implements GraphicLockView.OnGraphicLockListener {
    
        private TextView mTvIno;
        private GraphicLockView mGlGraphicLockView;
        private boolean isFirstSetPwd;
        private String mPassword;   //记录第一次绘制的密码
        private int type = 0;   //判断时登录还是设置密码
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_graphic_lock);
    
            initView();
        }
    
        private void initView() {
            mTvIno = (TextView) findViewById(R.id.agl_tv_info);
            mGlGraphicLockView = (GraphicLockView) findViewById(R.id.agl_gl_lock);
            isFirstSetPwd = true;
            mTvIno.setText("请绘制解锁图案");
    
            mGlGraphicLockView.setOnGraphicLockListener(this);
        }
    
        @Override
        public void setPwdSuccess(String password) {
            if (type == 0) {   //设置密码
                if (isFirstSetPwd) {
                    mTvIno.setText("请再次绘制图案进行确认");
                    mPassword = password;
                    isFirstSetPwd = false;
                } else {
                    if (mPassword.equals(password)) {
                        Toast.makeText(this, "设置密码成功", Toast.LENGTH_SHORT).show();
                        mTvIno.setText("你可以登录了");
                        type = 1;
                    } else {
                        Toast.makeText(this, "两次设置的密码不一致,请重试", Toast.LENGTH_SHORT).show();
                    }
                }
            } else if (type == 1) {  //登录
                if (mPassword.equals(password)) {
                    Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "密码错误,登录失败", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            isFirstSetPwd = true;
            mPassword = "";
        }
    
        @Override
        public void setPwdFailure() {
            if (type == 0) {
                mTvIno.setText("请至少连接四个点");
                Toast.makeText(this, "密码过短,设置失败", Toast.LENGTH_SHORT).show();
            } else if (type == 1) {
                mTvIno.setText("你可以登录了");
                Toast.makeText(this, "密码错误,登录失败", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    

    5.布局引用

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/agl_tv_info"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:textSize="18dp" />
    
        <TextView
            android:id="@+id/agl_tv_forget"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/agl_tv_info"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:text="忘记图案密码"
            android:visibility="gone" />
    
        <com.example.administrator.mydemo.graphiclock.GraphicLockView
            android:id="@+id/agl_gl_lock"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/agl_tv_forget" />
    
    </RelativeLayout>
    
    

    完成

    展开全文
  • 精美图案解锁

    2014-02-13 15:41:13
    精美图案解锁
  • flex图案解锁

    2018-02-13 13:45:04
    flashbuilder开发的图案解锁功能,经本人测试可以用的
  • Android图案解锁

    2018-09-14 16:48:58
    最近写项目,遇到一个图案解锁的功能,虽然不是什么新功能,但是这个功能写起来也挺复杂的,所以写了一个例子,传到这。和大家交流学习
  • 手势图案解锁

    2015-09-09 19:47:09
    图案解锁封装成jar包,支持图案的颜色改变、指纹解锁的样式、记录密码,里面有说明文档和jar包
  • Android 图案解锁

    千次阅读 2017-02-08 17:32:47
    图案解锁的功能在许多应用中都有用过,它比起数字解锁,带给用户的体验要好,今天就来一步一步实现这个功能。一、初始化初始化放在onDraw方法中,因为onDraw方法在绘制过程中会执行多次,我们设置一个标量isInit,使...

    首先还是看效果图。
    这里写图片描述 这里写图片描述
    图案解锁的功能在许多应用中都有用过,它比起数字解锁,带给用户的体验要好,今天就来一步一步实现这个功能。

    一、初始化

    初始化放在onDraw方法中,因为onDraw方法在绘制过程中会执行多次,我们设置一个标量isInit,使初始化只执行一次。

    @Override
        protected void onDraw(Canvas canvas) {
            if (!isInit) {
                init();
            }
        }
        private void init() {
    
            pressPaint.setColor(Color.YELLOW);
            pressPaint.setStrokeWidth(10);
            errorPaint.setColor(Color.RED);
            errorPaint.setStrokeWidth(10);
            int width = getWidth();
            int height = getHeight();
            int offset = Math.abs(width - height) / 2;
            int offsetX, offsetY;
            int space;
            if (width > height) //横屏
            {
                space = height / 4;
                offsetX = offset;
                offsetY = 0;
            } else {
                space = width / 4;
                offsetX = 0;
                offsetY = offset;
            }
    
            points[0][0] = new Point(offsetX + space, offsetY + space);
            points[0][1] = new Point(offsetX + space * 2, offsetY + space);
            points[0][2] = new Point(offsetX + space * 3, offsetY + space);
    
            points[1][0] = new Point(offsetX + space, offsetY + space * 2);
            points[1][1] = new Point(offsetX + space * 2, offsetY + space * 2);
            points[1][2] = new Point(offsetX + space * 3, offsetY + space * 2);
    
            points[2][0] = new Point(offsetX + space, offsetY + space * 3);
            points[2][1] = new Point(offsetX + space * 2, offsetY + space * 3);
            points[2][2] = new Point(offsetX + space * 3, offsetY + space * 3);
    
            normalBitap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);
            pressBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.press);
            errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.error);
            bitmapR = normalBitap.getWidth() / 2;
    
            isInit = true;
        }

    二、绘制九个点

    绘制前我们先需要确定这九个点的位置,为了适应手机屏的横竖屏切换,我们把这九个点的位置控制在屏幕最短长度范围内,也就是竖屏时我们以手机宽度为准,横屏时我们以手机的高度为准。然后以这个长度确定一个正方形区域,在这个正方形区域内画出这九个点并均匀分布,点的位置已在上面的初始化工作中计算好了,下面就直接绘制了。

    private void drawPoint(Canvas canvas) {
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[1].length; j++) {
                    Point point = points[i][j];
                    if (point.state == Point.STATE_NORMAL) {
                        canvas.drawBitmap(normalBitap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    } else if (point.state == Point.STATE_PRESS) {
                        canvas.drawBitmap(pressBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    } else {
                        canvas.drawBitmap(errorBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    }
    
                }
    
            }
        }

    这里需要注意画笔绘制的起始点和点所在的中心点有所偏差,所以代码中我们横纵坐标都减去了点的半径长度(bitmapR)。

    三、记录手指的绘制

    @Override
        public boolean onTouchEvent(MotionEvent event) {
    //        super.onTouchEvent(event);
            mouseX = event.getX();
            mouseY = event.getY();
            int[] ij;
            int i, j;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    resetPoint();
                    ij = getSelectPoint();
                    if (ij != null) {
                        isDraw = true;
                        i = ij[0];
                        j = ij[1];
                        points[i][j].state = Point.STATE_PRESS;
                        pressedPoints.add(points[i][j]);
                        passList.add(i * points.length + j);
    
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (isDraw) {
                        ij = getSelectPoint();
                        if (ij != null) {
                            i = ij[0];
                            j = ij[1];
                            //同一个点不能再添加到pressedPoints中
                            if (!pressedPoints.contains(points[i][j])) {
                                points[i][j].state = Point.STATE_PRESS;
                                pressedPoints.add(points[i][j]);
                                passList.add(i * points.length + j);
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
    
                    isDraw = false;
                    break;
            }
            invalidate();
            return true;
        }
    

    每次重新绘制前都重置所有数据

    public void resetPoint() {
    
            pressedPoints.clear();
            passList.clear();
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[0].length; j++) {
                    points[i][j].state = Point.STATE_NORMAL;
                }
            }
            invalidate();
        }

    判断手指划过的地方是否是图案中的某个点

    private int[] getSelectPoint() {
            Point pMouse = new Point(mouseX, mouseY);
            System.out.println("bitmapR:" + bitmapR);
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[0].length; j++) {
                    if (points[i][j].distance(pMouse) < bitmapR) {
                        int[] result = new int[2];
                        result[0] = i;
                        result[1] = j;
                        return result;
                    }
                }
            }
            return null;
        }

    返回的数组中记录点的坐标位置

    手指滑动过程中,还需要不断的画线,此时onDraw方法是这样的:

    @Override
        protected void onDraw(Canvas canvas) {
            if (!isInit) {
                init();
            }
    
            //画点
            drawPoint(canvas);
    
            //有点后,开始画线
            if (pressedPoints.size() > 0) {
                Point a = pressedPoints.get(0);
                for (int i = 0; i < pressedPoints.size(); i++) {
                    Point b = pressedPoints.get(i);
                    drawLine(canvas, a, b);
                    a = b;
                }
                if (isDraw) {
                    drawLine(canvas, a, new Point(mouseX, mouseY));
                }
            }
    
        }

    画线的方法:

    private void drawLine(Canvas canvas, Point a, Point b) {
            if (a.state == Point.STATE_PRESS) {
                canvas.drawLine(a.x, a.y, b.x, b.y, pressPaint);
            } else if (a.state == Point.STATE_ERROR) {
                canvas.drawLine(a.x, a.y, b.x, b.y, errorPaint);
            }
        }
    

    四、添加回调监听接口

    public interface OnDrawFinishedListener {
            boolean onDrawFinished(List<Integer> passList);
        }
    
        private OnDrawFinishedListener onDrawFinishedListener;
    
        public void setOnDrawFinishedListener(OnDrawFinishedListener onDrawFinishedListener) {
            this.onDrawFinishedListener = onDrawFinishedListener;
        }

    我们在手势抬起时调用这个监听方法,onTouchEvent(MotionEvent event)方法中:

    case MotionEvent.ACTION_UP:
                    boolean valid = false;
                    if (onDrawFinishedListener != null && isDraw) {
                        valid = onDrawFinishedListener.onDrawFinished(passList);
    //                    onDrawFinishedListener.onDrawFinished(passList);
                    }
    //                if (passList.size() <= 3) {
    //                    valid = false;
    //                }else {
    //                    valid = true;
    //                }
                    if (!valid) {
                        for (Point p : pressedPoints) {
                            p.state = Point.STATE_ERROR;
                        }
                    }
                    isDraw = false;
                    break;

    到这里就完成了图案解锁的自定义View。

    在Activity中使用

    GestureView myView = (GestureView) findViewById(R.id.view);
            myView.setOnDrawFinishedListener(new GestureView.OnDrawFinishedListener() {
                @Override
                public boolean onDrawFinished(List<Integer> passList) {
                    boolean flag = false;
                    if (passList.size() <= 3) {
                        Toast.makeText(GestureActivity.this, "图案绘制有误!", Toast.LENGTH_SHORT).show();
                        flag = false;
                    }else {
                        Toast.makeText(GestureActivity.this, "图案绘制完成!", Toast.LENGTH_SHORT).show();
                        flag = true;
                    }
    
                    return flag;
                }
            });

    最后附上GestureView的完整代码。

    public class GestureView extends View {
        private boolean isInit; //是否初始化
        private Point[][] points = new Point[3][3];
        private Paint pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
        private Paint pressPaint = new Paint();
        private Paint errorPaint = new Paint();
    
        private Bitmap normalBitap, pressBitmap, errorBitmap;
    
        private int bitmapR;
        private boolean isDraw;
        private ArrayList<Point> pressedPoints = new ArrayList<>();
        private ArrayList<Integer> passList = new ArrayList<>(); //记录所滑过的点的位置,第几个点,以便后续验证
    
        public GestureView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (!isInit) {
                init();
            }
    
            //画点
            drawPoint(canvas);
    
            //有点后,开始画线
            if (pressedPoints.size() > 0) {
                Point a = pressedPoints.get(0);
                for (int i = 0; i < pressedPoints.size(); i++) {
                    Point b = pressedPoints.get(i);
                    drawLine(canvas, a, b);
                    a = b;
                }
                if (isDraw) {
                    drawLine(canvas, a, new Point(mouseX, mouseY));
                }
            }
    
        }
    
        private void drawLine(Canvas canvas, Point a, Point b) {
            if (a.state == Point.STATE_PRESS) {
                canvas.drawLine(a.x, a.y, b.x, b.y, pressPaint);
            } else if (a.state == Point.STATE_ERROR) {
                canvas.drawLine(a.x, a.y, b.x, b.y, errorPaint);
            }
        }
    
        private void drawPoint(Canvas canvas) {
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[1].length; j++) {
                    Point point = points[i][j];
                    if (point.state == Point.STATE_NORMAL) {
                        canvas.drawBitmap(normalBitap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    } else if (point.state == Point.STATE_PRESS) {
                        canvas.drawBitmap(pressBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    } else {
                        canvas.drawBitmap(errorBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);
                    }
    
                }
    
            }
        }
    
        public void resetPoint() {
    
            pressedPoints.clear();
            passList.clear();
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[0].length; j++) {
                    points[i][j].state = Point.STATE_NORMAL;
                }
            }
            invalidate();
        }
    
        private void init() {
    
            pressPaint.setColor(Color.YELLOW);
            pressPaint.setStrokeWidth(10);
            errorPaint.setColor(Color.RED);
            errorPaint.setStrokeWidth(10);
            int width = getWidth();
            int height = getHeight();
            int offset = Math.abs(width - height) / 2;
            int offsetX, offsetY;
            int space;
            if (width > height) //横屏
            {
                space = height / 4;
                offsetX = offset;
                offsetY = 0;
            } else {
                space = width / 4;
                offsetX = 0;
                offsetY = offset;
            }
    
            points[0][0] = new Point(offsetX + space, offsetY + space);
            points[0][1] = new Point(offsetX + space * 2, offsetY + space);
            points[0][2] = new Point(offsetX + space * 3, offsetY + space);
    
            points[1][0] = new Point(offsetX + space, offsetY + space * 2);
            points[1][1] = new Point(offsetX + space * 2, offsetY + space * 2);
            points[1][2] = new Point(offsetX + space * 3, offsetY + space * 2);
    
            points[2][0] = new Point(offsetX + space, offsetY + space * 3);
            points[2][1] = new Point(offsetX + space * 2, offsetY + space * 3);
            points[2][2] = new Point(offsetX + space * 3, offsetY + space * 3);
    
            normalBitap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);
            pressBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.press);
            errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.error);
            bitmapR = normalBitap.getWidth() / 2;
    
            isInit = true;
        }
    
    
        float mouseX, mouseY;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    //        super.onTouchEvent(event);
            mouseX = event.getX();
            mouseY = event.getY();
            int[] ij;
            int i, j;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    resetPoint();
                    ij = getSelectPoint();
                    if (ij != null) {
                        isDraw = true;
                        i = ij[0];
                        j = ij[1];
                        points[i][j].state = Point.STATE_PRESS;
                        pressedPoints.add(points[i][j]);
                        passList.add(i * points.length + j);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (isDraw) {
                        ij = getSelectPoint();
                        if (ij != null) {
                            i = ij[0];
                            j = ij[1];
    
                            if (!pressedPoints.contains(points[i][j])) {
                                points[i][j].state = Point.STATE_PRESS;
                                pressedPoints.add(points[i][j]);
                                passList.add(i * points.length + j);
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    boolean valid = false;
                    if (onDrawFinishedListener != null && isDraw) {
                        valid = onDrawFinishedListener.onDrawFinished(passList);
    //                    onDrawFinishedListener.onDrawFinished(passList);
                    }
    //                if (passList.size() <= 3) {
    //                    valid = false;
    //                }else {
    //                    valid = true;
    //                }
                    if (!valid) {
                        for (Point p : pressedPoints) {
                            p.state = Point.STATE_ERROR;
                        }
                    }
                    isDraw = false;
                    break;
            }
            invalidate();
            return true;
        }
    
        private int[] getSelectPoint() {
            Point pMouse = new Point(mouseX, mouseY);
            for (int i = 0; i < points.length; i++) {
                for (int j = 0; j < points[0].length; j++) {
                    if (points[i][j].distance(pMouse) < bitmapR) {
                        int[] result = new int[2];
                        result[0] = i;
                        result[1] = j;
                        return result;
                    }
                }
            }
            return null;
        }
    
    
        public interface OnDrawFinishedListener {
            boolean onDrawFinished(List<Integer> passList);
        }
    
        private OnDrawFinishedListener onDrawFinishedListener;
    
        public void setOnDrawFinishedListener(OnDrawFinishedListener onDrawFinishedListener) {
            this.onDrawFinishedListener = onDrawFinishedListener;
        }
    }

    欢迎关注公众号。
    这里写图片描述

    展开全文
  • Android 图案解锁之九宫解锁源码 友友们我会更新更多的源码和大家分享 希望大家喜欢
  • win图案解锁

    2013-01-09 19:05:28
    想必大家都知道android的图案解锁吧? 这是一个适用于window平台的锁机软件 这个适用于win vista以前没aero的系统 小小软件,希望大家喜欢 待会上传支持aero系统的工具
  • 图案解锁的源码

    2015-05-28 10:20:39
    非常漂亮的图案解锁的源码,设置图案的时候有几个页面。欢迎下载,欢迎一起学习。
  • 仿手机图案解锁功能

    2016-03-21 15:23:48
    仿手机图案解锁功能
  • 这是图案解锁的项目,对大家 很有帮助的 ,不妨下载学习学习
  • ios手机图案解锁

    2014-04-24 15:37:11
    类似于手机图案解锁的功能,手机锁屏的功能
  • Android 图案解锁之九宫解锁源码.rar
  • Android 九宫格图案解锁源码,下载导入项目中运行。Android 九宫格图案解锁源码,下载导入项目中运行。
  • Android图案解锁源代码

    2015-07-22 15:58:01
    Android图案解锁的源代码,有注释,可方便扩展。
  • 图案解锁之九宫解锁源码.zip
  • 九宫格图案解锁 可自定义点图片和背景图 包含源代码
  • 我的期末作业需要基于ARM7S3C44B0X实现类似于安卓手机的图案解锁或者滑动解锁并且支持密码输入解锁希望专业技术人才能帮忙给我一个实例,或者提示我怎么去完成这个小项目 不知道是不是对于一个初学的大学生有难度
  • 一款Android平台下的图案解锁之九宫解锁源码,大家可以下载下来多学习学习,希望能给大家带来帮助。   
  • 主要为大家详细介绍了Android仿手机QQ图案解锁功能的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 自定义图案解锁控件

    万次阅读 2016-04-08 14:56:52
    看过极客学院自定义图案解锁控件教程,自己尝试写了一个。 效果图: 1.首先要绘制九个点,先看两张图片

    看过极客学院自定义图案解锁控件教程,自己尝试写了一个。

    效果图:


    1.首先要绘制九个点,先看两张图片

    通过上面的两张图片可以很容易计算出没个圆的圆心,也就是正方型的顶点坐标。并保存这九个点,要保存这九个点必须先创建一个点类。

    package com.example.chl.myapplication;
    
    /**
     * Created by chl on 16-4-6.
     */
    public class TuAnPoint {
        public static int STATE_NORMAL = 1;
        public static int STATE_PRESS = 2;
        public static int STATE_ERROR = 3;
        private float x;
        private float y;
        private int state = STATE_NORMAL;
    
        public TuAnPoint(float x, float y) {
            this.x = x;
            this.y = y;
        }
    
        public int getState() {
            return state;
        }
    
        public void setState(int state) {
            this.state = state;
        }
    
        public float getX() {
            return x;
        }
    
        public void setX(float x) {
            this.x = x;
        }
    
        public float getY() {
            return y;
        }
    
        public void setY(float y) {
            this.y = y;
        }
    
        /**
         * 重写equals方法来判断两个点对象是否相等
         * @param o
         * @return
         */
        @Override
        public boolean equals(Object o) {
            boolean bx = x == ((TuAnPoint) o).getX() ? true : false;
            boolean by = y == ((TuAnPoint) o).getY() ? true : false;
            boolean bb=false;
            if (bx && by){
                bb=true;
            }
            return bb;
        }
    }
    
    把这些坐标转化成我们定义的点对象并保存在List集合中:

    float width = getWidth();
            float height = getHeight();
            float offsetX = 0;
            float offsetY = 0;
            float offset = 0;
            float length = 0;
            offset = Math.abs(width - height) / 2f;
            if (width > height) {
                //横屏
                offsetX = offset;
                offsetY = 0;
    
                length = height / 4f;
            } else {
                //竖屏
                offsetX = 0;
                offsetY = offset;
                length = width / 4f;
            }
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + 3 * length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + 3 * length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + 3 * length));
            isInit = true;

    2.把保存的点绘制到屏幕上

    1)把点在不同状态下的资源图片加载为Bimap

    private Bitmap normal = BitmapFactory.decodeResource(getResources(), R.drawable.normal);
        private Bitmap error = BitmapFactory.decodeResource(getResources(), R.drawable.error);
        private Bitmap press = BitmapFactory.decodeResource(getResources(), R.drawable.press);

    2)绘制图片

    /**
         * 判断点的状态并绘制到屏幕上
         * @param canvas
         */
        private void drawPoint(Canvas canvas) {
            for (TuAnPoint tuAnPoint : listPoint) {
                if (tuAnPoint.getState() == TuAnPoint.STATE_PRESS) {
                    canvas.drawBitmap(normal, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                } else if (tuAnPoint.getState() ==TuAnPoint.STATE_PRESS) {
                    canvas.drawBitmap(press, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                } else {
                    canvas.drawBitmap(error, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                }
            }
        }

    因为drawBitmap方法参数是图片左上角的坐标,所以要减去一个图片的半径。


    3.onTouchEvent处理

     @Override
        public boolean onTouchEvent(MotionEvent event) {
            mouseX = event.getX();
            mouseY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (pressList.size() > 0) {
                        for (TuAnPoint p : pressList) {
                            p.setState(TuAnPoint.STATE_NORMAL);
                        }
                        pressList.clear();
                    }
                    getSelectPoint();
                    break;
                case MotionEvent.ACTION_MOVE:
                    getSelectPoint();
                    break;
                case MotionEvent.ACTION_UP:
                    int pressCount = 0;
                    for (TuAnPoint tuAnPoint : listPoint) {
                        if (!pressList.contains(tuAnPoint)) {
                            if (getPointsDistance(tuAnPoint.getX(), tuAnPoint.getY()) <= radius) {
                                pressCount++;
                            }
                        }
                    }
                    if (pressCount == 0 && pressList.size() > 0) {
                        mouseX = pressList.get(pressList.size() - 1).getX();
                        mouseY = pressList.get(pressList.size() - 1).getY();
                    }
                    boolean isFinish = false;
                    if (finishedListener != null) {
                        isFinish = finishedListener.onDrawFinished(pressList);
                        if (!isFinish) {
                            for (TuAnPoint point : pressList) {
                                point.setState(TuAnPoint.STATE_ERROR);
                            }
                        }
                    }
                    break;
    
            }
            invalidate();
            return true;
        }
    
        /**
         * 判断当前手指在屏幕上的点是否在九个点的范围之类,如果是则选中改点
         */
        private void getSelectPoint() {
            for (TuAnPoint tuAnPoint : listPoint) {
                if (getPointsDistance(tuAnPoint.getX(), tuAnPoint.getY()) <= radius) {
                    pressPoint = tuAnPoint;
                    if (pressList.size() > 0) {
                        TuAnPoint p = pressList.get(pressList.size() - 1);
    
    
                        for (TuAnPoint isPress : listPoint) {
                            boolean b = isLine(p, isPress, pressPoint);
                            //Log.d("tuanjiesuo", "bb:" + b);
                            if (b) {
                                if (((isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX()) && ((isPress.getY() > p.getY()) && (isPress.getY() < pressPoint.getY())))
                                        || ((isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX()) && ((isPress.getY() < p.getY()) && (isPress.getY() > pressPoint.getY())))) {
                                    //Log.d("tuanjiesuo","jinglai");
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                if ((isPress.getX() == p.getX() && isPress.getX() == pressPoint.getX() && isPress.getY() > p.getY() && isPress.getY() < pressPoint.getY())
                                        || (isPress.getX() == p.getX() && isPress.getX() == pressPoint.getX() && isPress.getY() < p.getY() && isPress.getY() > pressPoint.getY())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                if ((isPress.getY() == p.getY() && isPress.getY() == pressPoint.getY() && isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX())
                                        || (isPress.getY() == p.getY() && isPress.getY() == pressPoint.getY() && isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
    
                                }
                                if ((isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX() && isPress.getY() < p.getY() && isPress.getY() > pressPoint.getY())
                                        || (isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX() && isPress.getY() > p.getY() && isPress.getY() < pressPoint.getY())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                // break;
                            }
                        }
                    }
                    if (!pressList.contains(pressPoint)) {
    
                        pressList.add(pressPoint);
                    }
                    pressPoint.setState(TuAnPoint.STATE_PRESS);
    
                }
            }
    
        }
    
        /**
         * 判断isPress这个点是否在点p点pressPoint的直线上
         *
         * @param p
         * @param isPress
         * @param pressPoint
         * @return
         */
        private boolean isLine(TuAnPoint p, TuAnPoint isPress, TuAnPoint pressPoint) {
    
            boolean b = (p.getY() - isPress.getY()) * (pressPoint.getX() - p.getX()) == (p.getX() - isPress.getX()) * (pressPoint.getY() - p.getY()) ? true : false;
            return b;
        }
    
        /**
         * 计算传入的坐标到手指在屏幕上点的距离
         * @param x
         * @param y
         * @return
         */
        private float getPointsDistance(float x, float y) {
            float distance = (float) Math.sqrt((x - mouseX) * (x - mouseX) + (y - mouseY) * (y - mouseY));
            return distance;
        }
    
        /**
         * 提供给外部接口,当绘制完成后调用
         */
        public interface OnDrawFinishedListener {
            boolean onDrawFinished(List<TuAnPoint> pressList);
        }
    
        /**
         * 提供外部传入接口对象的方法
         * @param listener
         */
        public void setFinishedListener(OnDrawFinishedListener listener) {
            finishedListener = listener;
        }




    最后是完整的项目代码,注释比较完整:

    package com.example.chl.myapplication;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by chl on 16-4-6.
     */
    public class TuAnView extends View {
        private List<TuAnPoint> listPoint = new ArrayList<TuAnPoint>();
        private List<TuAnPoint> pressList = new ArrayList<TuAnPoint>();//被选中的点保存的集合
        private boolean isInit = false;
        private Bitmap normal = BitmapFactory.decodeResource(getResources(), R.drawable.normal);
        private Bitmap error = BitmapFactory.decodeResource(getResources(), R.drawable.error);
        private Bitmap press = BitmapFactory.decodeResource(getResources(), R.drawable.press);
        private float radius = normal.getWidth() / 2f;//图片半径
        private float mouseX = 0;
        private float mouseY = 0;
        private TuAnPoint pressPoint;
        private Paint errorPaint;//当密码错误时,画线的画笔
        private Paint pressPaint;//当密码正确时,画线的画笔
        private OnDrawFinishedListener finishedListener;
    
        public TuAnView(Context context) {
            super(context);
            // init();
        }
    
        public TuAnView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // init();
        }
    
        public TuAnView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // init();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (!isInit) {
                init();
            }
    
            drawPoint(canvas);//画点
            if (pressList.size() > 0) {//判断当有点被选中时才画线
                TuAnPoint a = pressList.get(0);//把集合中第一个点作为线的开始点
                for (int i = 1; i < pressList.size(); i++) {
                    drawLine(canvas, a, pressList.get(i));//画线
                    a = pressList.get(i);//把当前点作为下次画线的起点
                }
                drawLine(canvas, a, new TuAnPoint(mouseX, mouseY));//当有起点确定之后,手指在屏幕上滑动,但是没确定终点时画线
            }
        }
    
        /**
         * 画线
         * @param canvas
         * @param a
         * @param b
         */
        private void drawLine(Canvas canvas, TuAnPoint a, TuAnPoint b) {
            if (a.getState() == TuAnPoint.STATE_PRESS) {
                canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), pressPaint);
            } else {
                canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), errorPaint);
            }
    
        }
    
        /**
         * 判断点的状态并绘制到屏幕上
         * @param canvas
         */
        private void drawPoint(Canvas canvas) {
            for (TuAnPoint tuAnPoint : listPoint) {
                if (tuAnPoint.getState() == TuAnPoint.STATE_PRESS) {
                    canvas.drawBitmap(normal, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                } else if (tuAnPoint.getState() ==TuAnPoint.STATE_PRESS) {
                    canvas.drawBitmap(press, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                } else {
                    canvas.drawBitmap(error, tuAnPoint.getX() - radius, tuAnPoint.getY() - radius, null);
                }
            }
        }
    
        /**
         * 初始化
         */
        private void init() {
            errorPaint = new Paint();
            pressPaint = new Paint();
            errorPaint.setColor(Color.RED);
            errorPaint.setStrokeWidth(5);
            pressPaint.setColor(Color.YELLOW);
            pressPaint.setStrokeWidth(5);
            float width = getWidth();
            float height = getHeight();
            float offsetX = 0;
            float offsetY = 0;
            float offset = 0;
            float length = 0;
            offset = Math.abs(width - height) / 2f;
            if (width > height) {
                //横屏
                offsetX = offset;
                offsetY = 0;
    
                length = height / 4f;
            } else {
                //竖屏
                offsetX = 0;
                offsetY = offset;
                length = width / 4f;
            }
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + length));
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + 2 * length));
            listPoint.add(new TuAnPoint(offsetX + length, offsetY + 3 * length));
            listPoint.add(new TuAnPoint(offsetX + 2 * length, offsetY + 3 * length));
            listPoint.add(new TuAnPoint(offsetX + 3 * length, offsetY + 3 * length));
            isInit = true;
    
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mouseX = event.getX();
            mouseY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (pressList.size() > 0) {
                        for (TuAnPoint p : pressList) {
                            p.setState(TuAnPoint.STATE_NORMAL);
                        }
                        pressList.clear();
                    }
                    getSelectPoint();
                    break;
                case MotionEvent.ACTION_MOVE:
                    getSelectPoint();
                    break;
                case MotionEvent.ACTION_UP:
                    int pressCount = 0;
                    for (TuAnPoint tuAnPoint : listPoint) {
                        if (!pressList.contains(tuAnPoint)) {
                            if (getPointsDistance(tuAnPoint.getX(), tuAnPoint.getY()) <= radius) {
                                pressCount++;
                            }
                        }
                    }
                    if (pressCount == 0 && pressList.size() > 0) {
                        mouseX = pressList.get(pressList.size() - 1).getX();
                        mouseY = pressList.get(pressList.size() - 1).getY();
                    }
                    boolean isFinish = false;
                    if (finishedListener != null) {
                        isFinish = finishedListener.onDrawFinished(pressList);
                        if (!isFinish) {
                            for (TuAnPoint point : pressList) {
                                point.setState(TuAnPoint.STATE_ERROR);
                            }
                        }
                    }
                    break;
    
            }
            invalidate();
            return true;
        }
    
        /**
         * 判断当前手指在屏幕上的点是否在九个点的范围之类,如果是则选中改点
         */
        private void getSelectPoint() {
            for (TuAnPoint tuAnPoint : listPoint) {
                if (getPointsDistance(tuAnPoint.getX(), tuAnPoint.getY()) <= radius) {
                    pressPoint = tuAnPoint;
                    if (pressList.size() > 0) {
                        TuAnPoint p = pressList.get(pressList.size() - 1);//得到此次绘制线时的起始点
    
    
                        for (TuAnPoint isPress : listPoint) {
                            /**
                             * 以为有种情况是,当你选中第一个点后直接绕过第二个点而选中第三个点时,
                             * 默认第二个点也要选中,所以要做以下判断
                             */
                            boolean b = isLine(p, isPress, pressPoint);//判断是否还有其他点在起点和终点的直线上
                            //Log.d("tuanjiesuo", "bb:" + b);
                            if (b) {//如果有点在这条直线上,接下来判断改点是在这两点的中间还是两端,是中间的话就要默认选中
                                if (((isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX()) && ((isPress.getY() > p.getY()) && (isPress.getY() < pressPoint.getY())))
                                        || ((isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX()) && ((isPress.getY() < p.getY()) && (isPress.getY() > pressPoint.getY())))) {
                                    //Log.d("tuanjiesuo","jinglai");
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                if ((isPress.getX() == p.getX() && isPress.getX() == pressPoint.getX() && isPress.getY() > p.getY() && isPress.getY() < pressPoint.getY())
                                        || (isPress.getX() == p.getX() && isPress.getX() == pressPoint.getX() && isPress.getY() < p.getY() && isPress.getY() > pressPoint.getY())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                if ((isPress.getY() == p.getY() && isPress.getY() == pressPoint.getY() && isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX())
                                        || (isPress.getY() == p.getY() && isPress.getY() == pressPoint.getY() && isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
    
                                }
                                if ((isPress.getX() > p.getX() && isPress.getX() < pressPoint.getX() && isPress.getY() < p.getY() && isPress.getY() > pressPoint.getY())
                                        || (isPress.getX() < p.getX() && isPress.getX() > pressPoint.getX() && isPress.getY() > p.getY() && isPress.getY() < pressPoint.getY())) {
                                    isPress.setState(TuAnPoint.STATE_PRESS);
                                    if (!pressList.contains(isPress)) {
    
                                        pressList.add(isPress);
                                    }
                                }
                                // break;
                            }
                        }
                    }
                    if (!pressList.contains(pressPoint)) {
    
                        pressList.add(pressPoint);
                    }
                    pressPoint.setState(TuAnPoint.STATE_PRESS);
    
                }
            }
    
        }
    
        /**
         * 判断isPress这个点是否在点p点pressPoint的直线上
         *
         * @param p
         * @param isPress
         * @param pressPoint
         * @return
         */
        private boolean isLine(TuAnPoint p, TuAnPoint isPress, TuAnPoint pressPoint) {
    
            boolean b = (p.getY() - isPress.getY()) * (pressPoint.getX() - p.getX()) == (p.getX() - isPress.getX()) * (pressPoint.getY() - p.getY()) ? true : false;
            return b;
        }
    
        /**
         * 计算传入的坐标到手指在屏幕上点的距离
         * @param x
         * @param y
         * @return
         */
        private float getPointsDistance(float x, float y) {
            float distance = (float) Math.sqrt((x - mouseX) * (x - mouseX) + (y - mouseY) * (y - mouseY));
            return distance;
        }
    
        /**
         * 提供给外部接口,当绘制完成后调用
         */
        public interface OnDrawFinishedListener {
            boolean onDrawFinished(List<TuAnPoint> pressList);
        }
    
        /**
         * 提供外部传入接口对象的方法
         * @param listener
         */
        public void setFinishedListener(OnDrawFinishedListener listener) {
            finishedListener = listener;
        }
    }
    

    设置密码的Activity:

    package com.example.chl.myapplication;
    
    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.View;
    import android.widget.Toast;
    
    import java.util.List;
    
    public class SetTuAnActivity extends AppCompatActivity {
        private  TuAnView tuAnView;
        private    List<TuAnPoint> pressList;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_set_tu_an);
            tuAnView=(TuAnView)findViewById(R.id.tuanjiesuo);
            tuAnView.setFinishedListener(new TuAnView.OnDrawFinishedListener() {
                @Override
                public boolean onDrawFinished(List<TuAnPoint> pressList) {
                    SetTuAnActivity.this.pressList=pressList;
                    return true;
                }
            });
        }
        public void click(View view){
            switch (view.getId()){
                case R.id.button1:
                    ((MyAppliction)getApplication()).pressList=pressList;
                    Toast.makeText(this,"保存成功",Toast.LENGTH_SHORT).show();
                    finish();
                    break;
                case R.id.button2:
                    ((MyAppliction)getApplication()).pressList=null;
                    break;
            }
        }
    
    }

    测试密码的Activity:

    public class TwoActivity extends AppCompatActivity {
        private  TuAnView tuAnView;
        private List<TuAnPoint> list;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_two);
            list=((MyAppliction)getApplication()).pressList;
            tuAnView=(TuAnView)findViewById(R.id.two_tuan);
            tuAnView.setFinishedListener(new TuAnView.OnDrawFinishedListener() {
                @Override
                public boolean onDrawFinished(List<TuAnPoint> pressList) {
                    boolean b=true;
                    if (pressList.size()!=list.size()){
                        b=false;
                    }else {
                        for (int i = 0; i < pressList.size(); i++) {
                            if (!pressList.get(i).equals(list.get(i))) {
                                b = false;
                            }
    
                        }
                    }
                    if (b){
                        Toast.makeText(TwoActivity.this,"密码正确",Toast.LENGTH_SHORT).show();
                    }else {
                        Toast.makeText(TwoActivity.this,"密码错误",Toast.LENGTH_SHORT).show();
                    }
                    return b;
                }
            });
        }
    
    }



    展开全文
  • 主要为大家详细介绍了Unity3D使用GL实现图案解锁功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 手机图案解锁 permission denied解决方案

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,948
精华内容 1,979
关键字:

复杂的图案解锁