天天看點

類是支付寶的手勢密碼控件

為了加強APP的安全性,很多應用都會給自己添加手勢密碼的功能。

今天使用View實作了一個簡單手勢密碼的控件。

不多說有圖有真相:

類是支付寶的手勢密碼控件

View Java:

public class GesturesPasswordView extends View {

    /**
     * 監聽 繪制密碼完成
     */
    public interface OnGesturesFinish {
        public void onFinish(String keys);
    }

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

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

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

    public void setOnGesturesFinish(OnGesturesFinish l) {
        mOnGesturesFinish = l;
    }

    OnGesturesFinish mOnGesturesFinish;
    //  是否繪制觸摸線
    boolean isTouchLine = false;
    //  是否啟用繪制功能
    boolean isEnabled = true;
    //滑動狀态
    boolean isTouching = false;

    //繪圖區域
    Rect R_Image;
    //點資料
    PointData[] mPointData;
    Paint Paint_BG;
    //儲存繪制出來的密碼
    List<Object> Keys = new LinkedList<Object>();
    //最新選中的點
    PointData CurrentPoint;
    //目前觸摸位置
    float Touch_X, Touch_Y;


    void init() {
    }

    //計算點坐标
    void calculate() {
        Paint_BG = new Paint();
        Paint_BG.setAntiAlias(true);
        Paint_BG.setStrokeWidth();

        int min = Math.min(getWidth(), getHeight());
        R_Image = new Rect(, , min, min);
        mPointData = new PointData[];
        float Period = min / f;
        float offWith = getWidth() > min ? (getWidth() - min) /  : ;

        for (int y = ; y < ; y++) {
            for (int x = ; x < ; x++) {
                int index = y *  + x;
                int B_Y = y ==  ?  : y ==  ?  : ;
                int B_X = x ==  ?  : x ==  ?  : ;
                mPointData[index] = new PointData(Period * B_X + offWith, Period * B_Y, Period, mPointObservable, String.valueOf(index));
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (Paint_BG == null) calculate();

        //畫圓
        for (int i = ; i < ; i++) {
            mPointData[i].onDraw(canvas);
        }
        //畫延伸線
        if (isEnabled && CurrentPoint != null) {
            Paint_BG.setColor(PointData.Color_PointSelected);
            Paint_BG.setStyle(Paint.Style.FILL);
            canvas.drawLine(CurrentPoint.X, CurrentPoint.Y, Touch_X, Touch_Y, Paint_BG);
        }
    }
     //重置View
    public void reset() {
        for (int i = ; i < mPointData.length; i++)
            mPointData[i].isSelected = false;
        CurrentPoint = null;
        StringBuffer str = new StringBuffer();
        for (Object o : Keys)
            str.append(o.toString());
        Keys.clear();
        invalidate();
        isEnabled = true;
        if (mOnGesturesFinish != null) mOnGesturesFinish.onFinish(str.toString());
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        if (isEnabled) {
            Touch_X = event.getX();
            Touch_Y = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    if (isTouching) {
                        isEnabled = false;
                        isTouchLine = false;
                        invalidate();
                        if (Keys.size() != )
                            mHandler.sendMessageDelayed(mHandler.obtainMessage(), );
                        else isEnabled = true;
                    }
                    break;
                case MotionEvent.ACTION_DOWN:
                    isTouching = false;
                    for (int i = ; i < mPointData.length; i++) {
                        if (mPointData[i].isOverlap(Touch_X, Touch_Y)) {
                            isTouchLine = true;
                            isTouching = true;
                            mPointData[i].onTouchEvent(event);
                            break;
                        }
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (isTouching) {
                        for (int i = ; i < mPointData.length; i++) {
                            mPointData[i].onTouchEvent(event);
                        }
                    }
                    break;
            }
            invalidate();
        }
        return true;
    }
    //實作延時重置功能
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            reset();
        }
    };


    /**
     * 觀察選中點
     */
    PointObservable mPointObservable = new PointObservable() {

        @Override
        public void onSelected(PointData tag) {
            tag.setLastPoint(CurrentPoint == null ? tag : CurrentPoint);
            CurrentPoint = tag;
            Keys.add(CurrentPoint.Tag);
        }
    };


    /**
     * 觸摸點
     */
    public static class PointData {
        public float X, Y, Radius;
        public Object Tag;
        public boolean isSelected = false;

        RectF mRect;
        PointObservable mPointObservable;
        Paint paint;
        //上一個點
        PointData LastPoint;

        public PointData(float x, float y, float radius, PointObservable l) {
            this(x, y, radius, l, null);
        }

        public void setLastPoint(PointData last) {
            LastPoint = last;
        }

        public PointData(float x, float y, float radius, PointObservable l, Object tag) {
            X = x;
            Y = y;
            Radius = radius;
            mPointObservable = l;
            Tag = tag;
            paint = new Paint();
            paint.setColor();
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth();


            mRect = new RectF(X - radius, Y - radius, X + radius, Y + radius);

        }

        /**
         * 預設點的顔色
         */
        public static final int Color_PointDefualt = ;
        /**
         * 選中點的顔色
         */
        public static final int Color_PointSelected = ;

        public void onDraw(Canvas canvas) {
            canvas.save();
            if (!isSelected) {//未選中狀态
                paint.setColor(Color_PointDefualt);
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawCircle(X, Y, Radius, paint);
            } else {//0xffEF0601 //紅色
                paint.setColor(Color_PointSelected);
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawCircle(X, Y, Radius, paint);
                //選中狀态
                paint.setStyle(Paint.Style.FILL);
                paint.setColor();
                canvas.drawCircle(X, Y, Radius / , paint);
                paint.setColor(Color_PointSelected);
                canvas.drawCircle(X, Y, Radius / , paint);
                //繪制點的連線
                if (LastPoint != null && !LastPoint.equals(this)) {
                    canvas.drawLine(LastPoint.X, LastPoint.Y, X, Y, paint);
                }
            }
            canvas.restore();
        }

        public void onTouchEvent(MotionEvent e) {
            if (!isSelected) { //未選中的時候
                if (isOverlap(e.getX(), e.getY())) {
                    isSelected = true;
                    if (mPointObservable != null) mPointObservable.onSelected(this);
//                    }
                }
            }
        }


        /**
         * 獲得點到點的距離
         */
        static float getPointToPoint(float x1, float y1, float x2, float y2) {
            float x = x2 - x1;
            float y = y2 - y1;
            double num = Math.sqrt(x * x + y * y);
            return Double.isNaN(num) ? - : (float) num;
        }

        /**
         * 是否重疊
         */
        public boolean isOverlap(float x, float y) {
            float distance = getPointToPoint(x, y, X, Y);
            return distance != - && distance < Radius;
        }
    }


    private interface PointObservable {
        /**
         * 當
         */
        public void onSelected(PointData point);


    }

}
           

XML 引用:

<packagename.View.GesturesPasswordView
        android:id="@+id/view_GesturesPassword"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
           

最後監聽手勢密碼:

OnGesturesFinish mOnGesturesFinish = new GesturesPasswordView.OnGesturesFinish() {
        String KeyOld  = "";
        @Override
        public void onFinish(String keys) {
            if (!isSetPassword) {
                if (keys.length() < minkey) {
                    KeyOld = "";
                    TextInfo.setText("設定密碼\n至少連接配接3個點");
                    return;
                }
                if (TextUtils.isEmpty(KeyOld)) { //首次設定密碼
                    TextInfo.setText("請再輸入密碼");
                    KeyOld = keys;
                } else {
                    if (!keys.equals(KeyOld)) {
                        KeyOld = "";
                        TextInfo.setText("兩次密碼不相同,請重新輸入");
                    } else {//成功設定密碼
                        setPassword(getActivity(), keys); //儲存密碼
                        startAPP();
                    }
                }
            } else {
                if (!KeyOld.equals(keys)) {
                    TextInfo.setText("請重試");
                } else { //密碼驗證成功
                    startAPP();
                }
            }
        }
    };
           

設定監聽:

mGesturesPasswordView = (GesturesPasswordView) findViewById(R.id.view_GesturesPassword);
mGesturesPasswordView.setOnGesturesFinish(mOnGesturesFinish);
           

繼續閱讀