Android——自定义View实现9宫格解锁

来源:互联网 发布:hibernate怎么修改数据 编辑:程序博客网 时间:2024/05/22 12:34
自定义View
  • 1.实现一个子类继承View
  • 2.覆盖onDrow()函数,渲染图像
  • 3.覆盖onTouchEvent()函数
  • 4.监听按下、移动,松开手指的动作
  • 5.重新在onDrow()中渲染对应的的图像
效果图:

这是一个仿京东金融的一个九宫格解锁,最上面的日期显示使用的Time()获取到当前的时间,我们得到日期对其赋值就好了。
九宫格解锁有两个模式:CREATE_MODE  CHECK_MODE两种模式,一种是用来设置密码的模式,一种是输入密码的模式。验证登录密码会有三次机会,三次都输入错误会退出项目,忘记密码了也可以进行重新设置密码,非常的方便。重新设置手势密码这块没有进行验证,有兴趣的朋友可以用推送实现一个短信验证的效果。

package com.bawei.com.jingdongdemo;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.os.Handler;import android.os.Message;import android.support.annotation.IntDef;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import java.util.ArrayList;/** * Created by Wangrx on 2017/12/8. */public class UnlockView extends View {    public static final int CIRCLE_NORMAL = 1;//normal state of circle    public static final int CIRCLE_SELECTED = 2;//selected state of circle    public static final int CIRCLE_ERROR = 3;//error state of circle    public static final int CREATE_MODE = 22;//this mode is used for creating gesture    public static final int CHECK_MODE = 33;//this mode is used for checking gesture    @UnlockMode    private int mode;//define the mode    private int width;//the width of screen,valued in onMeasure    private int height;//the height of screen,valued in onMeasure    private int rootX;//root position of the line which can move    private int rootY;//root position of the line which can move    private Context ctx;    private ArrayList<Circle> circleList = new ArrayList<>();//store the circles on screen    private ArrayList<Circle> pathCircleList = new ArrayList<>();//store the selected circles    private Bitmap circletBmp;//used for drawing circles    private Canvas mCanvas;    private Paint cirNorPaint;//paint of normal state circles    private Paint cirSelPaint;//paint of selected state circles    private Paint smallCirSelPaint;//paint of selected state small circles    private Paint cirErrPaint;//paint of error state circles    private Paint smallcirErrPaint;//paint of error state small circles    private Paint pathPaint;//paint of the lines    private Path mPath;    private Path tempPath;    private int pathWidth = 3;//width of the paint of path    private int normalR = 15;//radius of small circles;    private int selectR = 30;//radius of big circles;    private int strokeWidth = 2;//width of big circles;    private int normalColor = Color.parseColor("#D5DBE8");//defalt color of normal state    private int selectColor = Color.parseColor("#508CEE");//defalt color of selected state    private int errorColor = Color.parseColor("#FF3153");//defalt color of error state    private boolean isUnlocking;    private boolean isShowError;    private boolean hasNewCircles;    private ArrayList<Integer> passList = new ArrayList<>();    private OnUnlockListener listener;//the listener of unlock    private CreateGestureListener createListener;//the listener of creating gesture    /**     * used for refresh the canvas after MotionEvent.ACTION_UP     */    private Handler handler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message msg) {            resetAll();            invalidate();            return true;        }    });    public UnlockView(Context context) {        super(context);        this.ctx = context;        strokeWidth = dip2px(ctx, strokeWidth);        normalR = dip2px(ctx, normalR);        selectR = dip2px(ctx, selectR);        pathWidth = dip2px(ctx, pathWidth);    }    public UnlockView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        this.ctx = context;        strokeWidth = dip2px(ctx, strokeWidth);        normalR = dip2px(ctx, normalR);        selectR = dip2px(ctx, selectR);        pathWidth = dip2px(ctx, pathWidth);    }    public UnlockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        this.ctx = context;        strokeWidth = dip2px(ctx, strokeWidth);        normalR = dip2px(ctx, normalR);        selectR = dip2px(ctx, selectR);        pathWidth = dip2px(ctx, pathWidth);    }    /**     * reset all states     */    private void resetAll() {        isShowError = false;        isUnlocking = false;        mPath.reset();        tempPath.reset();        pathCircleList.clear();        passList.clear();        for (Circle circle : circleList) {            circle.setState(CIRCLE_NORMAL);        }        pathPaint.setColor(selectColor);        cirSelPaint.setColor(selectColor);        smallCirSelPaint.setColor(selectColor);        clearCanvas();    }    @Override    protected void onDraw(Canvas canvas) {        canvas.drawBitmap(circletBmp, 0, 0, null);        for (int i = 0; i < circleList.size(); i++) {            drawCircles(circleList.get(i));        }        canvas.drawPath(mPath, pathPaint);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if (isShowError)            return true;        int curX = (int) event.getX();        int curY = (int) event.getY();        Circle circle = getOuterCircle(curX, curY);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                this.resetAll();                if (circle != null) {                    rootX = circle.getX();                    rootY = circle.getY();                    circle.setState(CIRCLE_SELECTED);                    pathCircleList.add(circle);                    tempPath.moveTo(rootX, rootY);                    addItem(circle.getPosition() + 1);                    isUnlocking = true;                }                break;            case MotionEvent.ACTION_MOVE:                if (isUnlocking) {                    mPath.reset();                    mPath.addPath(tempPath);                    mPath.moveTo(rootX, rootY);                    mPath.lineTo(curX, curY);                    handleMove(circle);                }                break;            case MotionEvent.ACTION_UP:                isUnlocking = false;                if (pathCircleList.size() > 0) {                    mPath.reset();                    mPath.addPath(tempPath);                    StringBuilder sb = new StringBuilder();                    for (Integer num : passList) {                        sb.append(num);                    }                    if (this.mode == CREATE_MODE) {                        if(createListener!=null){                            createListener.onGestureCreated(sb.toString());                        }else{                            Log.e("UnLockView","Please set CreateGestureListener first!");                        }                    } else if(this.mode == CHECK_MODE){                        if(listener!=null){                            if (listener.isUnlockSuccess(sb.toString())) {                                listener.onSuccess();                            } else {                                listener.onFailure();                                for (Circle circle1 : pathCircleList) {                                    circle1.setState(CIRCLE_ERROR);                                }                                pathPaint.setColor(errorColor);                            }                        }else{                            Log.e("UnLockView","Please set OnUnlockListener first!");                        }                    }else{                        try {                            throw new Exception("Please set mode first!");                        } catch (Exception e) {                            e.printStackTrace();                        }                    }                    isShowError = true;                    handler.postDelayed(new Runnable() {                        @Override                        public void run() {                            handler.sendEmptyMessage(0);                        }                    }, 1000);                }                break;        }        invalidate();        return true;    }    private synchronized void handleMove(Circle c) {        if (c != null&&!(c.getState()==CIRCLE_SELECTED)) {            c.setState(CIRCLE_SELECTED);            pathCircleList.add(c);            rootX = c.getX();            rootY = c.getY();            tempPath.lineTo(rootX, rootY);            addItem(c.getPosition() + 1);        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        width = getMeasuredWidth();        height = getMeasuredHeight();    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        if (mode != CHECK_MODE || mode != CREATE_MODE) {            Log.e("UnlockView", "Please set mode first!");        }        //init all path/paint        mPath = new Path();        tempPath = new Path();        pathPaint = new Paint();        pathPaint.setColor(selectColor);        pathPaint.setDither(true);        pathPaint.setAntiAlias(true);        pathPaint.setStyle(Paint.Style.STROKE);        pathPaint.setStrokeCap(Paint.Cap.ROUND);        pathPaint.setStrokeJoin(Paint.Join.ROUND);        pathPaint.setStrokeWidth(pathWidth);        //普通状态小圆画笔        circletBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        mCanvas = new Canvas(circletBmp);        cirNorPaint = new Paint();        cirNorPaint.setAntiAlias(true);        cirNorPaint.setDither(true);        cirNorPaint.setColor(normalColor);        //选中状态大圆画笔        cirSelPaint = new Paint();        cirSelPaint.setAntiAlias(true);        cirSelPaint.setDither(true);        cirSelPaint.setStyle(Paint.Style.STROKE);        cirSelPaint.setStrokeWidth(strokeWidth);        cirSelPaint.setColor(selectColor);        //选中状态小圆画笔        smallCirSelPaint = new Paint();        smallCirSelPaint.setAntiAlias(true);        smallCirSelPaint.setDither(true);        smallCirSelPaint.setColor(selectColor);        //出错状态大圆画笔        cirErrPaint = new Paint();        cirErrPaint.setAntiAlias(true);        cirErrPaint.setDither(true);        cirErrPaint.setStyle(Paint.Style.STROKE);        cirErrPaint.setStrokeWidth(strokeWidth);        cirErrPaint.setColor(errorColor);        //出错状态小圆画笔        smallcirErrPaint = new Paint();        smallcirErrPaint.setAntiAlias(true);        smallcirErrPaint.setDither(true);        smallcirErrPaint.setColor(errorColor);        //init all circles        int hor = width / 6;        int ver = height / 6;        if(!hasNewCircles){            for (int i = 0; i < 9; i++) {                int tempX = (i % 3 + 1) * 2 * hor - hor;                int tempY = (i / 3 + 1) * 2 * ver - ver;                Circle circle = new Circle(i, tempX, tempY, CIRCLE_NORMAL);                circleList.add(circle);            }        }        hasNewCircles=true;    }    /**     * called in onDraw for drawing all circles     *     * @param circle     */    private void drawCircles(Circle circle) {        switch (circle.getState()) {            case CIRCLE_NORMAL:                mCanvas.drawCircle(circle.getX(), circle.getY(), normalR, cirNorPaint);                break;            case CIRCLE_SELECTED:                mCanvas.drawCircle(circle.getX(), circle.getY(), selectR, cirSelPaint);                mCanvas.drawCircle(circle.getX(), circle.getY(), normalR, smallCirSelPaint);                break;            case CIRCLE_ERROR:                mCanvas.drawCircle(circle.getX(), circle.getY(), selectR, cirErrPaint);                mCanvas.drawCircle(circle.getX(), circle.getY(), normalR, smallcirErrPaint);                break;        }    }    /**     * clear canvas     */    private void clearCanvas() {        Paint p = new Paint();        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));        mCanvas.drawPaint(p);        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));        mPath.reset();        tempPath.reset();    }    /**     * J U S T  A  T O O L !     *     * @param context  Context     * @param dipValue value of dp     * @return     */    public static int dip2px(Context context, float dipValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dipValue * scale + 0.5f);    }    /**     * check whether the point is in a circle     *     * @param x     * @param y     * @return     */    @Nullable    private Circle getOuterCircle(int x, int y) {        for (int i = 0; i < circleList.size(); i++) {            Circle circle = circleList.get(i);            if ((x - circle.getX()) * (x - circle.getX()) + (y - circle.getY()) * (y - circle.getY()) <= normalR * normalR) {                if (circle.getState() != CIRCLE_SELECTED) {                    return circle;                }            }        }        return null;    }    /**     * check whether the password list contains the number     *     * @param num     * @return     */    private boolean arrContainsInt(int num) {        for (Integer value : passList) {            if (num == value) {                return true;            }        }        return false;    }    /**     * put the num into password list     *     * @param num     */    private void addItem(Integer num) {        if (!arrContainsInt(num)) {            passList.add(num);        }    }    /**     * Create Mode Listener     */    interface CreateGestureListener {        void onGestureCreated(String result);    }    public void setGestureListener(CreateGestureListener listener) {        this.createListener = listener;    }    /**     * Check Mode Listener     */    interface OnUnlockListener {        boolean isUnlockSuccess(String result);        void onSuccess();        void onFailure();    }    public void setOnUnlockListener(OnUnlockListener listener) {        this.listener = listener;    }    public void setPathWidth(int pathWidth) {        this.pathWidth = pathWidth;    }    public void setNormalR(int normalR) {        this.normalR = normalR;    }    public void setSelectR(int selectR) {        this.selectR = selectR;    }    public void setNormalColor(int normalColor) {        this.normalColor = normalColor;    }    public void setSelectColor(int selectColor) {        this.selectColor = selectColor;    }    public void setErrorColor(int errorColor) {        this.errorColor = errorColor;    }    public void setMode(@UnlockMode int mode) {        this.mode = mode;    }    class Circle {        /**         * position of the circle         */        private int position;        private int x;        private int y;        /**         * the state of circle         */        private int state;        public Circle() {        }        public Circle(int position, int x, int y, int state) {            this.position = position;            this.x = x;            this.y = y;            this.state = state;        }        public int getPosition() {            return position;        }        public void setPosition(int position) {            this.position = position;        }        public int getX() {            return x;        }        public void setX(int x) {            this.x = x;        }        public int getY() {            return y;        }        public void setY(int y) {            this.y = y;        }        public int getState() {            return state;        }        public void setState(int state) {            this.state = state;        }    }    /**     * It's an annotation     */    @IntDef({CREATE_MODE, CHECK_MODE})    @interface UnlockMode {    }}
MainActivity
public class PwdActivity extends AppCompatActivity {    int count = 0;    private UnlockView mUnlockView;    private String pwd;    private SharedPreferences sharedPreferences;    private SharedPreferences.Editor edit;    private SimpleDraweeView img;    private TextView time;    private TextView forget;    private TextView type;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_pwd);        forget = (TextView) findViewById(R.id.forget);        type = (TextView) findViewById(R.id.type);        ImmersionUtils immersionUtils = new ImmersionUtils();        immersionUtils.setImmersion(getWindow(), getSupportActionBar());        time = (TextView) findViewById(R.id.time);        Time t=new Time(); // or Time t=new Time("GMT+8"); 加上Time Zone资料        t.setToNow(); // 取得系统时间。        int year = t.year;        int month = t.month;        int date = t.monthDay;        int hour = t.hour;        time.setText(date+"");        img = (SimpleDraweeView) findViewById(R.id.img);        mUnlockView = (UnlockView) findViewById(R.id.unlock);        sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE);        if (sharedPreferences.getInt("flage",0)==1){            img.setImageURI(sharedPreferences.getString("img", "img"));        }else {            img.setImageResource(R.mipmap.user);        }        forget.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                edit = sharedPreferences.edit();                edit.putBoolean("key",false);                edit.commit();                onResume();                count=0;            }        });    }    @Override    protected void onResume() {        super.onResume();        boolean key = sharedPreferences.getBoolean("key", false);        pwd = sharedPreferences.getString("pwd", "pwd");        if (key) {            mUnlockView.setMode(UnlockView.CHECK_MODE);            type.setText("请登录你的密码");            mUnlockView.setOnUnlockListener(new UnlockView.OnUnlockListener() {                @Override                public boolean isUnlockSuccess(String result) {                    if (result.equals(pwd)) {                        return true;                    } else {                        return false;                    }                }                @Override                public void onSuccess() {                    Toast.makeText(PwdActivity.this, "登录成功", Toast.LENGTH_SHORT).show();                    Intent intent = new Intent(PwdActivity.this, MainActivity.class);                    startActivity(intent);                    finish();                }                @Override                public void onFailure() {                    count++;                    if (count == 3) {                        finish();                    } else {                        Toast.makeText(PwdActivity.this, "密码错误,还有" + (3 - count) + "次机会", Toast.LENGTH_SHORT).show();                    }                }            });        } else {            mUnlockView.setMode(UnlockView.CREATE_MODE);            type.setText("请设置您的手势密码!");            mUnlockView.setGestureListener(new UnlockView.CreateGestureListener()            {                @Override                public void onGestureCreated (String result){                    Log.i("zzz", "onGestureCreated: " + result);                    pwd = result;                    edit = sharedPreferences.edit();                    edit.putBoolean("key",true);                    edit.putString("pwd",pwd);                    edit.commit();                    Toast.makeText(PwdActivity.this, "密码设置成功!", Toast.LENGTH_SHORT).show();                    mUnlockView.setMode(UnlockView.CHECK_MODE);                    onResume();                }            });        }    }}
布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:fresco="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.bawei.com.jingdongdemo.PwdActivity">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical"        >        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content">            <TextView                android:id="@+id/time"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="08"                android:textSize="40sp"                android:textStyle="bold"                android:layout_marginTop="20dp"                android:layout_marginLeft="20dp"                />            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="Dec"                android:textSize="17sp"                android:textStyle="bold"                android:layout_toRightOf="@+id/time"                android:layout_marginTop="40dp"                android:layout_marginLeft="5dp"                />        </RelativeLayout>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="未来的事情做好计划不去担心"            android:textSize="20sp"            android:layout_marginLeft="20dp"            />        <com.facebook.drawee.view.SimpleDraweeView            android:id="@+id/img"            android:layout_width="100dp"            android:layout_height="100dp"            fresco:roundAsCircle="true"            android:layout_marginTop="30dp"            android:layout_marginBottom="30dp"            android:layout_gravity="center_horizontal"            fresco:placeholderImage="@mipmap/user"/>        <com.bawei.com.jingdongdemo.UnlockView            android:id="@+id/unlock"            android:layout_width="400dp"            android:layout_height="400dp"            android:layout_gravity="center_horizontal"            />        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:orientation="horizontal"            android:layout_marginTop="120dp"            android:layout_gravity="center_horizontal"            >            <TextView                android:id="@+id/forget"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="忘记手势密码"                android:textSize="17sp"                />            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="|"                android:layout_marginLeft="10dp"                android:layout_marginRight="10dp"                android:textSize="17sp"                />            <TextView                android:id="@+id/type"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="请设置您的手势密码!"                android:textColor="#f00"                android:textSize="17sp"                />        </LinearLayout>    </LinearLayout></RelativeLayout>


原创粉丝点击