android 自定义view实现九宫格手势解锁

来源:互联网 发布:淘宝防排查 编辑:程序博客网 时间:2024/04/26 19:43

刚才我使用银行APP时,看见了这个效果,趁着下班时间,就写了。
先看下效果图:
这里写图片描述
这里写图片描述
我先说下我的思路:
1: 先计算每个点 XY坐标点,然后存储在integerList中,然后画九个点,此时我把它叫为:画板的原始状态!
2:复写onTouchEvent事件, 然后每次监听ACTION_DOWN,ACTION_MOVE,ACTION_UP状态;

  1. ACTION_DOWN:我们需要将画板至于原始状态。
  2. ACTION_MOVE:我们需要计算遍历integerList的点,然后跟move点做比较,如果距离distance < radius , 就表明有选中了该点,此时我们把改点的下标放进indexList中;然后每一次都刷新一次view。
  3. ACTION_UP:离开动作,就涉及到自己的业务逻辑了,在这我写了一个回调,可以根据回调做相应的业务逻辑。对了,我写的点不能小于4个,也就是indexList.size()>=4;

对了,integerList里点的存储的顺序是:从左上角开始为第一个,然后,第二个……..第九个;

具体的看下图:

这里写图片描述

具体的看下代码:

package com.app.test.testlineproject;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;import android.support.v4.content.ContextCompat;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.Toast;import java.util.ArrayList;import java.util.List;/** * Created by ${liumegnqiang} on 2017/6/28. */public class LockLineView extends View {    private float height;// view的高度    private float wight;    private float radius ;//圆的半径    private float companyWidth;//因为是三个点,所以将width分为三分 也就是 companyWidth = width / 3;    private float companyHeight;    private List<PaintBean> integerList = new ArrayList<>();//九个点的坐标    private  List<Integer> indexList = new ArrayList<>();//连接的点(不重复)    private float moveX;//每次移动的X坐标    private float moveY;//每次移动的Y坐标    private OnLessPaintListener onLessPaintListener;    private boolean isUP = false;//判断是否是UP状态,是的话,就去除多余的连接 , 只连接点与点    private int widthLine = 4;//线的宽度    //R.color.line 可以自定义color    private int selectColor = ContextCompat.getColor(getContext(),R.color.line);//圆选中的颜色    private int unSelectColor = Color.GRAY;//圆未选中的颜色    private int lineColor = ContextCompat.getColor(getContext(),R.color.line);//线的颜色    public LockLineView(Context context) {        super(context);    }    public LockLineView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public LockLineView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        height = getMeasuredHeight();        wight = getMeasuredWidth();        /**         * 这三个数值的计算比例,可根据自己的需求, 更改!!!         */        companyWidth = wight / 3;        companyHeight = height / 3;        radius = wight / 16;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        Paint paint = new Paint();        paint.setAntiAlias(true);        paint.setStyle(Paint.Style.FILL);        /**         * 画九宫格         */        paint.setColor(unSelectColor);//原点的颜色        for(int i = 0;i < 3;i++){            for(int j = 0;j < 3 ;j++ ){                RectF rectF = new RectF();                rectF.left = j * companyWidth + companyWidth / 2 - radius;                rectF.right = j * companyWidth + companyWidth / 2 + radius;                rectF.top = i * companyHeight + companyHeight / 2 - radius;                rectF.bottom = i * companyHeight + companyHeight / 2 + radius;                integerList.add(new PaintBean(j * companyWidth + companyWidth / 2, i * companyHeight + companyHeight / 2));                canvas.drawOval(rectF, paint);            }        }        /**         * 画连接的线         */        if(indexList.size() == 0){            return;        }        paint.setColor(lineColor);//线的颜色        paint.setStrokeWidth(widthLine);//线的宽度        for(int i = 1;i < indexList.size();i++){            canvas.drawLine(integerList.get(indexList.get(i - 1)).getPaintX(), integerList.get(indexList.get(i - 1)).getPaintY(),                    integerList.get(indexList.get(i)).getPaintX(),integerList.get(indexList.get(i)).getPaintY(), paint);        }        if(!isUP){            canvas.drawLine(integerList.get(indexList.get(indexList.size() - 1)).getPaintX(), integerList.get(indexList.get(indexList.size() - 1)).getPaintY(),                    moveX, moveY, paint);        }        /**         * 画选中的点         */        paint.setColor(selectColor);//选中圆的颜色        for(int i = 0;i < indexList.size();i++){            PaintBean paintBean = integerList.get(indexList.get(i));            RectF rectF = new RectF();            rectF.left = paintBean.getPaintX() - radius;            rectF.right = paintBean.getPaintX() + radius;            rectF.top = paintBean.getPaintY() - radius;            rectF.bottom = paintBean.getPaintY() + radius;            canvas.drawOval(rectF, paint);        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:{                Message message = new Message();                message.what = 3;                handler.sendMessage(message);                break;            }            case MotionEvent.ACTION_MOVE:{                moveX = event.getX();                moveY = event.getY();                for(int i = 0;i < integerList.size();i++){                    PaintBean paintBean = integerList.get(i);                    float distance = (float)Math.sqrt((paintBean.getPaintX()-moveX)  * (paintBean.getPaintX()-moveX)                            + (paintBean.getPaintY() - moveY) * (paintBean.getPaintY() - moveY));                    /**                     * 有一个问题:                     * 就是当你测试时,可以中间隔一个原点,                     * 也就是该原点没有被选中,这时你可以修改该下面的判断,进行修改;                     * 当然 你感觉没问题的话 就不用改了。。。                     */                    if(distance < radius){                        if(!indexList.contains(i)){                            indexList.add(i);                        }                    }                }                Message message = new Message();                message.what = 1;                handler.sendMessage(message);                break;            }            case MotionEvent.ACTION_UP:{                Message message = new Message();                message.what = 2;                handler.sendMessage(message);                break;            }        }        return true;    }    private Handler handler  = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (msg.what){                case 1:{                    isUP = false;                    integerList.clear();                    invalidate();                    break;                }                case 2:{                    isUP = true;                    if(indexList.size() < 4){                        /**                         * TODO  连点数少于四个时,业务逻辑处理                         */                        Toast.makeText(getContext(),"连点数不能少于4个", Toast.LENGTH_SHORT).show();                        if(onLessPaintListener != null){                            onLessPaintListener.onLessPaintListener();//少于四个时,回调给view层                        }                        integerList.clear();                        indexList.clear();                    }else{                        /**                         * TODO  连点数大于四个时,业务逻辑处理                         */                    }                    invalidate();                    break;                }                case 3:{                    isUP = false;                    integerList.clear();                    indexList.clear();                    invalidate();                    break;                }            }        }    };    /**     * 在view层设置参数之后(比如:setWidthLine(4)),可调用此方法,刷新LockLineView;     */    public void setPaint(){        postInvalidate();    }    /**     * 少于四个点数时,回调     */    interface OnLessPaintListener{        void onLessPaintListener();    }    public OnLessPaintListener getOnLessPaintListener() {        return onLessPaintListener;    }    public void setOnLessPaintListener(OnLessPaintListener onLessPaintListener) {        this.onLessPaintListener = onLessPaintListener;    }    public float getRadius() {        return radius;    }    public void setRadius(float radius) {        this.radius = radius;    }    public int getWidthLine() {        return widthLine;    }    public void setWidthLine(int widthLine) {        this.widthLine = widthLine;    }    public int getLineColor() {        return lineColor;    }    public void setLineColor(int lineColor) {        this.lineColor = lineColor;    }    public int getUnSelectColor() {        return unSelectColor;    }    public void setUnSelectColor(int unSelectColor) {        this.unSelectColor = unSelectColor;    }    public int getSelectColor() {        return selectColor;    }    public void setSelectColor(int selectColor) {        this.selectColor = selectColor;    }}

有的小伙伴可能会问:为什么不用postInvalidate()呢?
其实我刚开始用的就是这个方法,但是我发现滑动的move和刷新view不同步,所以就用了invalidate(),自己控制刷新view。
至于颜色的,可以通过相应的get方法进行设置。对了 这个view的宽高,需要自己去调试!

最后附上源码:
http://download.csdn.net/detail/lmq121210/9884371

原创粉丝点击