九宫格手势解锁控件

此九宫格手势自定义控件虽然比较简陋,但是也基本实现了如下功能:

1.默认显示九个小内圆,实心圆。   另外提供了,设置其半径,初始化颜色,以及选中之后的颜色

2.如果选中了小内圆,对应的也显示外圆环。 另外提供了,选中时候的颜色,以及失败的时候的颜色的设置

3.连线的绘制,在触摸滑动的过程中选中的点为联络站进行绘制路径。另外提供了 触摸时候连线的颜色以及失败的时候的颜色设置

4.手指离开触摸屏的时候,记录了对应的密码数字。并提供回调接口,可传递给外界进行校验判断。

注意:逻辑不复杂,但是需要注意的是,测量的时候对于AT_MOST如何处理。另外对自定义View设置padding的情况下如何处理,使其生效。

下面直接贴代码:

1.自定义View

package com.example.win10.smallprojecttest;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.logging.Handler;

/**
 * Created by WIN10 on 2019/2/11.
 */

public class MyLockView extends View {

    public Context context;
    private int screenWidth;
    private int screenHeight;

    int width;//去掉内边距之后的宽度,可用来画画的宽度
    int height;//此去掉内边距之后的高度,可用来画画的高度

    //内圆的画笔,color1默认,color11 被选中时候的颜色
    private int radio1 = 50;
    private int color1 = Color.GRAY;
    private int color11 = Color.BLUE;
    private Paint paint1;

    //外圆的画笔参数
    private int radio2 = 80;
    private int color2 = Color.BLUE;
    private int color22 = Color.RED;
    private Paint paint2;

    //连线画笔的参数
    private int color3 = Color.BLUE;
    private int color33 = Color.RED;
    private Paint paint3;

    int left0 = 0;//大圆环的最左边的坐标   在无pading时为0
    int top0 = 0;//大圆环的最上边的坐标     在无padding时为0

    //下面是九个点
    Point point1 = new Point();
    Point point2 = new Point();
    Point point3 = new Point();
    Point point4 = new Point();
    Point point5 = new Point();
    Point point6 = new Point();
    Point point7 = new Point();
    Point point8 = new Point();
    Point point9 = new Point();
    ArrayList<Point> pointList = new ArrayList<>();



    public void setSmallCircle(int radio,int defaultColor,int selectColor){
        radio1=radio;
        color1=defaultColor;
        color11=selectColor;

    }

    public void setLargeCircle(int radio,int defaultColor,int errorColor){
        radio2=radio;
        color2=defaultColor;
        color22=errorColor;
    }

    public void setLine(int defaultColor,int errorColor){
        color3=defaultColor;
        color33=errorColor;
    }


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

    public MyLockView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyLockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;

        init();

    }


    public void init() {
        screenWidth = ScreenUtil.getScreenWidth(context);
        screenHeight = ScreenUtil.getScreenHeight(context);
        paint1 = new Paint();
        paint1.setAntiAlias(true);
        paint1.setColor(color1);
        paint1.setStyle(Paint.Style.FILL);

        paint2 = new Paint();
        paint2.setAntiAlias(true);
        paint2.setColor(color2);
        paint2.setStyle(Paint.Style.STROKE);
        paint2.setStrokeWidth(6);

        paint3 = new Paint();
        paint3.setAntiAlias(true);
        paint3.setColor(color3);
        paint3.setStyle(Paint.Style.STROKE);
        paint3.setStrokeWidth(6);
    }

    //根据可用View的尺寸去设置9点
    public void setAllPoint(int width, int height) {

        int delX = (width - radio2 * 2) / 2;
        int delY = (height - radio2 * 2) / 2;
        point1.set(left0 + radio2, top0 + radio2);
        point2.set(point1.x + delX, point1.y);
        point3.set(point2.x + delX, point1.y);

        point4.set(point1.x, point1.y + delY);
        point5.set(point4.x + delX, point4.y);
        point6.set(point5.x + delX, point4.y);

        point7.set(point4.x, point4.y + delY);
        point8.set(point7.x + delX, point7.y);
        point9.set(point8.x + delX, point7.y);
        pointList.add(point1);
        pointList.add(point2);
        pointList.add(point3);
        pointList.add(point4);
        pointList.add(point5);
        pointList.add(point6);
        pointList.add(point7);
        pointList.add(point8);
        pointList.add(point9);
    }


    //测量,在AT_MOST下进行处理
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widths = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heights = MeasureSpec.getSize(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST) {
            widths = (int) (screenWidth * 0.8);

        }
        if (heightMode == MeasureSpec.AT_MOST) {
            heights = (int) (screenHeight * 0.6);
        }
        setMeasuredDimension(widths, heights);

    }

    //重新设置布局,处理Padding情况
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();
        super.onLayout(changed, left + paddingLeft, top + paddingTop, right - paddingRight, bottom - paddingBottom);

        width = right - left - paddingLeft - paddingRight;
        height = bottom - top - paddingTop - paddingBottom;
        left0 = paddingLeft;
        top0 = paddingTop;

        setAllPoint(width, height);
        postInvalidate();
    }


    //画画
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Point point = null;
        //没有选中的内圆,还是灰色的
        for (int i = 0; i < pointList.size(); i++) {
            paint1.setColor(color1);
            point = pointList.get(i);
            canvas.drawCircle(point.x, point.y, radio1, paint1);
        }

        if (arrayListSelect.size() > 0) {
            paint1.setColor(color11);
            Path path = new Path();
            path.moveTo(pointList.get(arrayListSelect.get(0)).x, pointList.get(arrayListSelect.get(0)).y);
            for (int j = 0; j < arrayListSelect.size(); j++) {
                Integer index = arrayListSelect.get(j);
                point = pointList.get(index);
                canvas.drawCircle(point.x, point.y, radio1, paint1);
                canvas.drawCircle(point.x, point.y, radio2, paint2);
                if (arrayListSelect.size() > 1 && j > 0) {
                    path.lineTo(point.x, point.y);
                }
            }
            if (isTouching&&ScreenUtil.dist(xMove,yMove,point.x,point.y)>radio2) {
                path.lineTo(xMove, yMove);
            }
            canvas.drawPath(path, paint3);

        }

    }

    int xMove;
    int yMove;
    boolean isTouching = false;
    ArrayList<Integer> arrayListSelect = new ArrayList<>();//存储触摸到的点,不重复添加

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                isTouching = true;
                arrayListSelect.clear();
                int x = (int) event.getX();
                int y = (int) event.getY();
                getOuterCircle(x, y);
                break;

            case MotionEvent.ACTION_MOVE:
                xMove = (int) event.getX();
                yMove = (int) event.getY();
                getOuterCircle(xMove, yMove);
                postInvalidate();
                break;

            case MotionEvent.ACTION_UP:
                if (guesterListener != null) {
                    guesterListener.getGuesterNum(arrayListSelect);
                }
                isTouching = false;
                new android.os.Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        arrayListSelect.clear();
                        init();
                        postInvalidate();
                    }
                }, 1500);

                break;

        }
        return true;
    }


    private int getOuterCircle(int x, int y) {
        Point point;
        for (int i = 0; i < pointList.size(); i++) {
            point = pointList.get(i);
            if (x > point.x - radio1 && x < point.x + radio1 && y > point.y - radio1 && y < point.y + radio1) {
                if (!arrayListSelect.contains(i)) {
                    arrayListSelect.add(i);
                }
            }
        }
        return -1;
    }

    GuesterListener guesterListener;

    public void setOnGuesterLisetener(GuesterListener lisetener) {
        guesterListener = lisetener;
    }

    public interface GuesterListener {

        void getGuesterNum(ArrayList<Integer> arrayList);

    }


    public void passWordError(ArrayList arrayList){
        arrayListSelect=arrayList;
        paint3.setColor(color33);
        paint2.setColor(color22);
        postInvalidate();
    }

}

2.工具类:

package com.example.win10.smallprojecttest;

import android.content.Context;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;

import static java.lang.Math.pow;

/**
 * Created by WIN10 on 2019/2/11.
 */

public class ScreenUtil {
    public static int height;
    public static int width;
    private static ScreenUtil instance;
    private Context context;

    private ScreenUtil(Context context) {
        this.context = context;
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(dm);
        width = dm.widthPixels;
        height = dm.heightPixels;
    }

    public static ScreenUtil getInstance(Context context) {
        if (instance == null) {
            instance = new ScreenUtil(context);
        }
        return instance;
    }


    /**
     * 得到手机屏幕的宽度, pix单位
     */

    /**
     * 获得通知栏的高度
     *
     * @return
     */
    public static int getStatusHeight(Context context) {
        int resid = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resid > 0) {
            return context.getResources().getDimensionPixelSize(resid);
        }
        return -1;
    }

    /**
     * 得到手机屏幕的宽度, pix单位
     */
    public int getScreenWidth() {
        return width;
    }

    //获取屏幕的宽度
    public static int getScreenWidth(Context context) {
        WindowManager manager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        return display.getWidth();
    }

    //获取屏幕的高度
    public static int getScreenHeight(Context context) {
        WindowManager manager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        return display.getHeight();
    }

    //px转dp
    public static int dp2px(Context context, float dp) {
        return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f);
    }

    //两个点之间的距离
  public static int dist( int x1, int y1, int x2, int y2 ){

        double x,y;

        x = Math.pow(x1-x2,2);
        y =Math. pow(y1-y2,2);

        return (int) Math.sqrt(x+y);

    }


}

3.使用:

package com.example.win10.smallprojecttest;

import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    MyLockView myLockView;
    String mima="";
    int time=5;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myLockView= findViewById(R.id.test);
        myLockView.setSmallCircle(50, Color.GREEN,Color.BLUE);
        myLockView.setOnGuesterLisetener(new MyLockView.GuesterListener() {
            @Override
            public void getGuesterNum(ArrayList<Integer> arrayList) {
                mima = "";
                if (time > 0) {
                    time--;
                    if (arrayList != null && arrayList.size() > 0) {
                        for (int i = 0; i < arrayList.size(); i++) {
                            Integer integer = arrayList.get(i);
                            mima = mima + integer;
                        }
                    }
                    if (!TextUtils.isEmpty(mima) && mima.equals("012345")) {
                        Toast.makeText(MainActivity.this, "登陆成功", Toast.LENGTH_LONG).show();
                        time=5;
                    } else {
                        myLockView.passWordError(arrayList);
                        Toast.makeText(MainActivity.this, "您还有" + time + "次机会", Toast.LENGTH_LONG).show();

                    }

                }else{
                    Toast.makeText(MainActivity.this, "您已经连续五次输入错误,账号已经冻结", Toast.LENGTH_LONG).show();
                }
            }
        });
    }
}

资源文件就不贴了,随便试试就行。

猜你喜欢

转载自blog.csdn.net/lk2021991/article/details/89505997