Android之九宫格解锁的实现

 

    <ignore_js_op>                                                 

 

下面是最重要的那个LocusPassWordView:

/**
 * 
 * 九宫格解锁
 * 
 * @author way
 * 
 */
public class LocusPassWordView extends View {
        private float w = 0;
        private float h = 0;

        //
        private boolean isCache = false;
        //
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        //
        private Point[][] mPoints = new Point[3][3];
        // 圆的半径
        private float r = 0;
        // 选中的点
        private List<Point> sPoints = new ArrayList<Point>();
        private boolean checking = false;
        private Bitmap locus_round_original;// 圆点初始状态时的图片
        private Bitmap locus_round_click;// 圆点点击时的图片
        private Bitmap locus_round_click_error;// 出错时圆点的图片
        private Bitmap locus_line;// 正常状态下线的图片
        private Bitmap locus_line_semicircle;
        private Bitmap locus_line_semicircle_error;
        private Bitmap locus_arrow;// 线的移动方向
        private Bitmap locus_line_error;// 错误状态下的线的图片
        private long CLEAR_TIME = 0;// 清除痕迹的时间
        private int passwordMinLength = 5;// 密码最小长度
        private boolean isTouch = true; // 是否可操作
        private Matrix mMatrix = new Matrix();
        private int lineAlpha = 50;// 连线的透明度

        public LocusPassWordView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
        }

        public LocusPassWordView(Context context, AttributeSet attrs) {
                super(context, attrs);
        }

        public LocusPassWordView(Context context) {
                super(context);
        }

        @Override
        public void onDraw(Canvas canvas) {
                if (!isCache) {
                        initCache();
                }
                drawToCanvas(canvas);
        }

        private void drawToCanvas(Canvas canvas) {

                // mPaint.setColor(Color.RED);
                // Point p1 = mPoints[1][1];
                // Rect r1 = new Rect(p1.x - r,p1.y - r,p1.x +
                // locus_round_click.getWidth() - r,p1.y+locus_round_click.getHeight()-
                // r);
                // canvas.drawRect(r1, mPaint);
                // 画所有点
                for (int i = 0; i < mPoints.length; i++) {
                        for (int j = 0; j < mPoints[i].length; j++) {
                                Point p = mPoints[i][j];
                                if (p.state == Point.STATE_CHECK) {
                                        canvas.drawBitmap(locus_round_click, p.x - r, p.y - r,
                                                        mPaint);
                                } else if (p.state == Point.STATE_CHECK_ERROR) {
                                        canvas.drawBitmap(locus_round_click_error, p.x - r,
                                                        p.y - r, mPaint);
                                } else {
                                        canvas.drawBitmap(locus_round_original, p.x - r, p.y - r,
                                                        mPaint);
                                }
                        }
                }
                // mPaint.setColor(Color.BLUE);
                // canvas.drawLine(r1.left+r1.width()/2, r1.top, r1.left+r1.width()/2,
                // r1.bottom, mPaint);
                // canvas.drawLine(r1.left, r1.top+r1.height()/2, r1.right,
                // r1.bottom-r1.height()/2, mPaint);

                // 画连线
                if (sPoints.size() > 0) {
                        int tmpAlpha = mPaint.getAlpha();
                        mPaint.setAlpha(lineAlpha);
                        Point tp = sPoints.get(0);
                        for (int i = 1; i < sPoints.size(); i++) {
                                Point p = sPoints.get(i);
                                drawLine(canvas, tp, p);
                                tp = p;
                        }
                        if (this.movingNoPoint) {
                                drawLine(canvas, tp, new Point((int) moveingX, (int) moveingY));
                        }
                        mPaint.setAlpha(tmpAlpha);
                        lineAlpha = mPaint.getAlpha();
                }

        }

        /**
         * 初始化Cache信息
         * 
         * @param canvas
         */
        private void initCache() {

                w = this.getWidth();
                h = this.getHeight();
                float x = 0;
                float y = 0;

                // 以最小的为准
                // 纵屏
                if (w > h) {
                        x = (w - h) / 2;
                        w = h;
                }
                // 横屏
                else {
                        y = (h - w) / 2;
                        h = w;
                }

                locus_round_original = BitmapFactory.decodeResource(
                                this.getResources(), R.drawable.locus_round_original);
                locus_round_click = BitmapFactory.decodeResource(this.getResources(),
                                R.drawable.locus_round_click);
                locus_round_click_error = BitmapFactory.decodeResource(
                                this.getResources(), R.drawable.locus_round_click_error);

                locus_line = BitmapFactory.decodeResource(this.getResources(),
                                R.drawable.locus_line);
                locus_line_semicircle = BitmapFactory.decodeResource(
                                this.getResources(), R.drawable.locus_line_semicircle);

                locus_line_error = BitmapFactory.decodeResource(this.getResources(),
                                R.drawable.locus_line_error);
                locus_line_semicircle_error = BitmapFactory.decodeResource(
                                this.getResources(), R.drawable.locus_line_semicircle_error);

                locus_arrow = BitmapFactory.decodeResource(this.getResources(),
                                R.drawable.locus_arrow);
                // Log.d("Canvas w h :", "w:" + w + " h:" + h);

                // 计算圆圈图片的大小
                float canvasMinW = w;
                if (w > h) {
                        canvasMinW = h;
                }
                float roundMinW = canvasMinW / 8.0f * 2;
                float roundW = roundMinW / 2.f;
                //
                float deviation = canvasMinW % (8 * 2) / 2;
                x += deviation;
                x += deviation;

                if (locus_round_original.getWidth() > roundMinW) {
                        float sf = roundMinW * 1.0f / locus_round_original.getWidth(); // 取得缩放比例,将所有的图片进行缩放
                        locus_round_original = BitmapUtil.zoom(locus_round_original, sf);
                        locus_round_click = BitmapUtil.zoom(locus_round_click, sf);
                        locus_round_click_error = BitmapUtil.zoom(locus_round_click_error,
                                        sf);

                        locus_line = BitmapUtil.zoom(locus_line, sf);
                        locus_line_semicircle = BitmapUtil.zoom(locus_line_semicircle, sf);

                        locus_line_error = BitmapUtil.zoom(locus_line_error, sf);
                        locus_line_semicircle_error = BitmapUtil.zoom(
                                        locus_line_semicircle_error, sf);
                        locus_arrow = BitmapUtil.zoom(locus_arrow, sf);
                        roundW = locus_round_original.getWidth() / 2;
                }

                mPoints[0][0] = new Point(x + 0 + roundW, y + 0 + roundW);
                mPoints[0][1] = new Point(x + w / 2, y + 0 + roundW);
                mPoints[0][2] = new Point(x + w - roundW, y + 0 + roundW);
                mPoints[1][0] = new Point(x + 0 + roundW, y + h / 2);
                mPoints[1][1] = new Point(x + w / 2, y + h / 2);
                mPoints[1][2] = new Point(x + w - roundW, y + h / 2);
                mPoints[2][0] = new Point(x + 0 + roundW, y + h - roundW);
                mPoints[2][1] = new Point(x + w / 2, y + h - roundW);
                mPoints[2][2] = new Point(x + w - roundW, y + h - roundW);
                int k = 0;
                for (Point[] ps : mPoints) {
                        for (Point p : ps) {
                                p.index = k;
                                k++;
                        }
                }
                r = locus_round_original.getHeight() / 2;// roundW;
                isCache = true;
        }

        /**
         * 画两点的连接
         * 
         * @param canvas
         * @param a
         * @param b
         */
        private void drawLine(Canvas canvas, Point a, Point b) {
                float ah = (float) MathUtil.distance(a.x, a.y, b.x, b.y);
                float degrees = getDegrees(a, b);
                // Log.d("=============x===========", "rotate:" + degrees);
                canvas.rotate(degrees, a.x, a.y);

                if (a.state == Point.STATE_CHECK_ERROR) {
                        mMatrix.setScale((ah - locus_line_semicircle_error.getWidth())
                                        / locus_line_error.getWidth(), 1);
                        mMatrix.postTranslate(a.x, a.y - locus_line_error.getHeight()
                                        / 2.0f);
                        canvas.drawBitmap(locus_line_error, mMatrix, mPaint);
                        canvas.drawBitmap(locus_line_semicircle_error, a.x
                                        + locus_line_error.getWidth(),
                                        a.y - locus_line_error.getHeight() / 2.0f, mPaint);
                } else {
                        mMatrix.setScale((ah - locus_line_semicircle.getWidth())
                                        / locus_line.getWidth(), 1);
                        mMatrix.postTranslate(a.x, a.y - locus_line.getHeight() / 2.0f);
                        canvas.drawBitmap(locus_line, mMatrix, mPaint);
                        canvas.drawBitmap(locus_line_semicircle, a.x + ah
                                        - locus_line_semicircle.getWidth(),
                                        a.y - locus_line.getHeight() / 2.0f, mPaint);
                }

                canvas.drawBitmap(locus_arrow, a.x, a.y - locus_arrow.getHeight()
                                / 2.0f, mPaint);

                canvas.rotate(-degrees, a.x, a.y);

        }

        public float getDegrees(Point a, Point b) {
                float ax = a.x;// a.index % 3;
                float ay = a.y;// a.index / 3;
                float bx = b.x;// b.index % 3;
                float by = b.y;// b.index / 3;
                float degrees = 0;
                if (bx == ax) // y轴相等 90度或270
                {
                        if (by > ay) // 在y轴的下边 90
                        {
                                degrees = 90;
                        } else if (by < ay) // 在y轴的上边 270
                        {
                                degrees = 270;
                        }
                } else if (by == ay) // y轴相等 0度或180
                {
                        if (bx > ax) // 在y轴的下边 90
                        {
                                degrees = 0;
                        } else if (bx < ax) // 在y轴的上边 270
                        {
                                degrees = 180;
                        }
                } else {
                        if (bx > ax) // 在y轴的右边 270~90
                        {
                                if (by > ay) // 在y轴的下边 0 - 90
                                {
                                        degrees = 0;
                                        degrees = degrees
                                                        + switchDegrees(Math.abs(by - ay),
                                                                        Math.abs(bx - ax));
                                } else if (by < ay) // 在y轴的上边 270~0
                                {
                                        degrees = 360;
                                        degrees = degrees
                                                        - switchDegrees(Math.abs(by - ay),
                                                                        Math.abs(bx - ax));
                                }

                        } else if (bx < ax) // 在y轴的左边 90~270
                        {
                                if (by > ay) // 在y轴的下边 180 ~ 270
                                {
                                        degrees = 90;
                                        degrees = degrees
                                                        + switchDegrees(Math.abs(bx - ax),
                                                                        Math.abs(by - ay));
                                } else if (by < ay) // 在y轴的上边 90 ~ 180
                                {
                                        degrees = 270;
                                        degrees = degrees
                                                        - switchDegrees(Math.abs(bx - ax),
                                                                        Math.abs(by - ay));
                                }

                        }

                }
                return degrees;
        }

        /**
         * 1=30度 2=45度 4=60度
         * 
         * @param tan
         * @return
         */
        private float switchDegrees(float x, float y) {
                return (float) MathUtil.pointTotoDegrees(x, y);
        }

        /**
         * 取得数组下标
         * 
         * @param index
         * @return
         */
        public int[] getArrayIndex(int index) {
                int[] ai = new int[2];
                ai[0] = index / 3;
                ai[1] = index % 3;
                return ai;
        }

        /**
         * 
         * 检查
         * 
         * @param x
         * @param y
         * @return
         */
        private Point checkSelectPoint(float x, float y) {
                for (int i = 0; i < mPoints.length; i++) {
                        for (int j = 0; j < mPoints[i].length; j++) {
                                Point p = mPoints[i][j];
                                if (RoundUtil.checkInRound(p.x, p.y, r, (int) x, (int) y)) {
                                        return p;
                                }
                        }
                }
                return null;
        }

        /**
         * 重置
         */
        private void reset() {
                for (Point p : sPoints) {
                        p.state = Point.STATE_NORMAL;
                }
                sPoints.clear();
                this.enableTouch();
        }

        /**
         * 判断点是否有交叉 返回 0,新点 ,1 与上一点重叠 2,与非最后一点重叠
         * 
         * @param p
         * @return
         */
        private int crossPoint(Point p) {
                // 重叠的不最后一个则 reset
                if (sPoints.contains(p)) {
                        if (sPoints.size() > 2) {
                                // 与非最后一点重叠
                                if (sPoints.get(sPoints.size() - 1).index != p.index) {
                                        return 2;
                                }
                        }
                        return 1; // 与最后一点重叠
                } else {
                        return 0; // 新点
                }
        }

        /**
         * 添加一个点
         * 
         * @param point
         */
        private void addPoint(Point point) {
                this.sPoints.add(point);
        }

        /**
         * 转换为String
         * 
         * @param points
         * @return
         */
        private String toPointString() {
                if (sPoints.size() > passwordMinLength) {
                        StringBuffer sf = new StringBuffer();
                        for (Point p : sPoints) {
                                sf.append(",");
                                sf.append(p.index);
                        }
                        return sf.deleteCharAt(0).toString();
                } else {
                        return "";
                }
        }

        boolean movingNoPoint = false;
        float moveingX, moveingY;

        @Override
        public boolean onTouchEvent(MotionEvent event) {
                // 不可操作
                if (!isTouch) {
                        return false;
                }

                movingNoPoint = false;

                float ex = event.getX();
                float ey = event.getY();
                boolean isFinish = false;
                boolean redraw = false;
                Point p = null;
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: // 点下
                        // 如果正在清除密码,则取消
                        if (task != null) {
                                task.cancel();
                                task = null;
                                Log.d("task", "touch cancel()");
                        }
                        // 删除之前的点
                        reset();
                        p = checkSelectPoint(ex, ey);
                        if (p != null) {
                                checking = true;
                        }
                        break;
                case MotionEvent.ACTION_MOVE: // 移动
                        if (checking) {
                                p = checkSelectPoint(ex, ey);
                                if (p == null) {
                                        movingNoPoint = true;
                                        moveingX = ex;
                                        moveingY = ey;
                                }
                        }
                        break;
                case MotionEvent.ACTION_UP: // 提起
                        p = checkSelectPoint(ex, ey);
                        checking = false;
                        isFinish = true;
                        break;
                }
                if (!isFinish && checking && p != null) {

                        int rk = crossPoint(p);
                        if (rk == 2) // 与非最后一重叠
                        {
                                // reset();
                                // checking = false;

                                movingNoPoint = true;
                                moveingX = ex;
                                moveingY = ey;

                                redraw = true;
                        } else if (rk == 0) // 一个新点
                        {
                                p.state = Point.STATE_CHECK;
                                addPoint(p);
                                redraw = true;
                        }
                        // rk == 1 不处理

                }

                // 是否重画
                if (redraw) {

                }
                if (isFinish) {
                        if (this.sPoints.size() == 1) {
                                this.reset();
                        } else if (this.sPoints.size() < passwordMinLength
                                        && this.sPoints.size() > 0) {
                                // mCompleteListener.onPasswordTooMin(sPoints.size());
                                error();
                                clearPassword();
                                Toast.makeText(this.getContext(), "密码太短,请重新输入!",
                                                Toast.LENGTH_SHORT).show();
                        } else if (mCompleteListener != null) {
                                if (this.sPoints.size() >= passwordMinLength) {
                                        this.disableTouch();
                                        mCompleteListener.onComplete(toPointString());
                                }

                        }
                }
                this.postInvalidate();
                return true;
        }

        /**
         * 设置已经选中的为错误
         */
        private void error() {
                for (Point p : sPoints) {
                        p.state = Point.STATE_CHECK_ERROR;
                }
        }

        /**
         * 设置为输入错误
         */
        public void markError() {
                markError(CLEAR_TIME);
        }

        /**
         * 设置为输入错误
         */
        public void markError(final long time) {
                for (Point p : sPoints) {
                        p.state = Point.STATE_CHECK_ERROR;
                }
                this.clearPassword(time);
        }

        /**
         * 设置为可操作
         */
        public void enableTouch() {
                isTouch = true;
        }

        /**
         * 设置为不可操作
         */
        public void disableTouch() {
                isTouch = false;
        }

        private Timer timer = new Timer();
        private TimerTask task = null;

        /**
         * 清除密码
         */
        public void clearPassword() {
                clearPassword(CLEAR_TIME);
        }

        /**
         * 清除密码
         */
        public void clearPassword(final long time) {
                if (time > 1) {
                        if (task != null) {
                                task.cancel();
                                Log.d("task", "clearPassword cancel()");
                        }
                        lineAlpha = 130;
                        postInvalidate();
                        task = new TimerTask() {
                                public void run() {
                                        reset();
                                        postInvalidate();
                                }
                        };
                        Log.d("task", "clearPassword schedule(" + time + ")");
                        timer.schedule(task, time);
                } else {
                        reset();
                        postInvalidate();
                }

        }

        //
        private OnCompleteListener mCompleteListener;

        /**
         * @param mCompleteListener
         */
        public void setOnCompleteListener(OnCompleteListener mCompleteListener) {
                this.mCompleteListener = mCompleteListener;
        }

        /**
         * 取得密码
         * 
         * @return
         */
        private String getPassword() {
                SharedPreferences settings = this.getContext().getSharedPreferences(
                                this.getClass().getName(), 0);
                return settings.getString("password", ""); // , "0,1,2,3,4,5,6,7,8"
        }

        /**
         * 密码是否为空
         * 
         * @return
         */
        public boolean isPasswordEmpty() {
                return StringUtil.isEmpty(getPassword());
        }

        public boolean verifyPassword(String password) {
                boolean verify = false;
                if (com.way.util.StringUtil.isNotEmpty(password)) {
                        // 或者是超级密码
                        if (password.equals(getPassword())) {
                                verify = true;
                        }
                }
                return verify;
        }

        /**
         * 设置密码
         * 
         * @param password
         */
        public void resetPassWord(String password) {
                SharedPreferences settings = this.getContext().getSharedPreferences(
                                this.getClass().getName(), 0);
                Editor editor = settings.edit();
                editor.putString("password", password);
                editor.commit();
        }

        public int getPasswordMinLength() {
                return passwordMinLength;
        }

        public void setPasswordMinLength(int passwordMinLength) {
                this.passwordMinLength = passwordMinLength;
        }

        /**
         * 轨迹球画完成事件
         * 
         * @author way
         */
        public interface OnCompleteListener {
                /**
                 * 画完了
                 * 
                 * @param str
                 */
                public void onComplete(String password);
        }
}
View Code

代码下载

posted @ 2013-11-08 11:52  无恨星晨  阅读(10180)  评论(3编辑  收藏  举报