Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

自定义九宫格解锁控件

$
0
0

前言

九宫格手势解锁已经是非常常见的手机解锁方式,支付宝等一些软件也都曾经使用过,感觉还是很高大上的。在github已经有很好的开源控件,大家可以去自己搜索,我自己写了一个自定义的九宫格控件,作为练习作业。

效果图

我不会做动图,就凑合看吧……
这里写图片描述

先贴自定义属性代码
<!-- 九宫格解锁-->
<declare-styleable name="DrawPointLineUnlockView">
<!-- 行数 -->
<attr name="columns" format="integer"/>
<!-- 列数 -->
<attr name="rows" format="integer"/>
<!-- 连线的宽度 -->
<attr name="lineWidth" format="dimension"/>
<!-- 九宫格的大小 -->
<attr name="pointRadius" format="dimension"/>
<!-- 九宫格的颜色 -->
<attr name="pointColor" format="color" />
</declare-styleable>

我把自定义属性的连线宽度,作为了九宫格的实心圆的半径和外面的空心圆的边框宽度。

贴代码

package lzp.com.interestlibrary.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

import lzp.com.interestlibrary.R;
import lzp.com.interestlibrary.view.bean.DrawPoint;

/**
 * Created by li.zhipeng on 16/11/17.
 * <p>
 * 九宫格解锁View
 * <p>
 * 可以定制颜色和九宫格的数量
 */

public class DrawPointLineUnlockView extends View {

    /**
     * 手势按下时的x坐标
     */
    private float xDown = -1;

    /**
     * 手势按下时的y坐标
     */
    private float yDown = -1;
    /**
     * 手势y移动时的x坐标
     */
    private float xMove = -1;

    /**
     * 手势移动时的y坐标
     */
    private float yMove = -1;

    /**
     * 画笔的宽度
     */
    private int lineWidth = 10;

    /**
     * 每一个九宫格的大小
     */
    private int pointRadius = 30;

    /**
     * 九宫格的横向个数
     */
    private int columeCount = 3;

    /**
     * 九宫格的行数
     */
    private int rowCount = 3;

    /**
     * 九宫格的颜色
     */
    private int pointColor = Color.parseColor("#000000");

    /**
     * 画笔
     */
    private Paint paint;

    /**
     * 保存所有的九宫格的点的数组
     */
    private ArrayList<DrawPoint> pointsList;

    /**
     * 已经绘制的九宫格的点
     */
    private ArrayList<DrawPoint> drawPoints;

    /**
     * 进行判断的点
     * <p>
     * 只创建一个,不返回的创建对象,节省内存
     */
    private DrawPoint tempPoint;

    /**
     * 是否要进行绘制
     */
    private boolean needDraw;

    /**
     * 密码
     * */
    private String passward;

    /**
     * 解锁解锁回调
     * */
    private OnDrawPointUnlockResultListener listener;

    public void setPassward(String passward){
        this.passward = passward;
    }

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

    public DrawPointLineUnlockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取自定义属性的值
        TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.DrawPointLineUnlockView);
        // 画笔的宽度
        lineWidth = typedArray.getDimensionPixelSize(R.styleable.DrawPointLineUnlockView_lineWidth, 10);
        // 每一个九宫格的大小
        pointRadius = typedArray.getDimensionPixelSize(R.styleable.DrawPointLineUnlockView_pointRadius, 30);
        // 九宫格的横向个数
        columeCount = typedArray.getInt(R.styleable.DrawPointLineUnlockView_columns, 3);
        // 九宫格的列数
        rowCount = typedArray.getInt(R.styleable.DrawPointLineUnlockView_rows, 3);
        // 九宫格的行数
        pointColor = typedArray.getColor(R.styleable.DrawPointLineUnlockView_pointColor, Color.parseColor("#000000"));
        typedArray.recycle();

        // 防止View不进行绘制,执行onDraw()方法
        setWillNotDraw(false);

        pointsList = new ArrayList<>();
        drawPoints = new ArrayList<>();
        tempPoint = new DrawPoint(-1, pointRadius, lineWidth);
        // 初始化画笔
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(pointColor);
        paint.setStrokeWidth(lineWidth);
        paint.setPathEffect(new CornerPathEffect(5));
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDown = event.getX();
                yDown = event.getY();
                // 判断是否这个点是九宫格的某一个点,否则不进行绘制
                tempPoint.x = xDown;
                tempPoint.y = yDown;
                int index = pointsList.indexOf(tempPoint);
                if (index != -1) {
                    needDraw = true;
                    DrawPoint point = pointsList.get(index);
                    drawPoints.add(point);
                    xDown = point.x;
                    yDown = point.y;
                } else {
                    needDraw = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (needDraw) {
                    xMove = event.getX();
                    yMove = event.getY();
                    // 判断是否这个点是九宫格的某一个点,如果是的话,连接这个点
                    tempPoint.x = xMove;
                    tempPoint.y = yMove;
                    int moveIndex = pointsList.indexOf(tempPoint);
                    // 判断这个点是否是九宫格的点  且 这个点并没有被连接过
                    if (moveIndex != -1 && !drawPoints.contains(tempPoint)) {
                        DrawPoint point = pointsList.get(moveIndex);
                        drawPoints.add(point);
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if (needDraw) {
                    xDown = -1;
                    yDown = -1;
                    xMove = -1;
                    yMove = -1;
                    // 监听回调
                    if (listener != null){
                        String unlockResult = returnPwd();
                        listener.onUnlock(unlockResult, unlockResult.equals(passward));
                    }
                    // 清除所有的连接点
                    drawPoints.clear();
                    // 重绘
                    invalidate();
                }
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 画出所有的九宫格的点
        for (DrawPoint point : pointsList) {
            point.draw(canvas, paint);
        }
        // 如果正在解锁且已经划过了某些九宫格,画出他们之间的连线
        int size = drawPoints.size() - 1;
        if (needDraw && size >= 0) {
            // 只有一个起点,画出第一个点和手指位置的连线
            if (size == 0) {
                DrawPoint point = drawPoints.get(0);
                canvas.drawLine(point.x, point.y, xMove, yMove, paint);
            }
            // 多个点,画出点和点之间的连线
            else {
                for (int i = 0; i < size; i++) {
                    DrawPoint point = drawPoints.get(i);
                    DrawPoint nextPoint = drawPoints.get(i + 1);
                    canvas.drawLine(point.x, point.y, nextPoint.x, nextPoint.y, paint);
                }
                // 画出最后一个点和当前手指位置之间的连线
                DrawPoint point = drawPoints.get(size);
                canvas.drawLine(point.x, point.y, xMove, yMove, paint);
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // 测量当前的宽高 来绘制指定个数的九宫格
        float width = getWidth() - pointRadius * 2;
        float height = getHeight() - pointRadius * 2;

        // 获取padding值
        float paddingLeft = getPaddingLeft();
        float paddingRight = getPaddingRight();
        float paddingTop = getPaddingTop();
        float paddingBottom = getPaddingBottom();


        // 求出每个点的起始位置
        float xDistance = (width - paddingTop - paddingBottom) / (columeCount - 1);
        float yDistance = (height - paddingLeft - paddingRight) / (rowCount - 1);

        // 计算每一个九宫格的圆心
        for (int i = 0; i < rowCount; i++) {
            for (int j = 0; j < columeCount; j++) {
                DrawPoint pointF = new DrawPoint(j + rowCount * i, pointRadius, lineWidth);
                pointF.y = yDistance * i + pointRadius + paddingTop;
                pointF.x = xDistance * j + pointRadius + paddingLeft;
                pointsList.add(pointF);
            }
        }
    }

    /**
     * 返回密码
     * */
    private String returnPwd(){
        StringBuilder builder = new StringBuilder();
        for (DrawPoint point : drawPoints){
            builder.append(point.getValue());
        }
        return builder.toString();
    }

    /**
     * 解锁回调
     * */
    public interface OnDrawPointUnlockResultListener{
        /**
         *  @param passward 解锁的结果密码
         *  @param success 与设置的密码进行匹配的结果
         * */
        void onUnlock(String passward, boolean success);
    }

    public void setOnDrawPointUnlockResultListener(OnDrawPointUnlockResultListener listener){
        this.listener = listener;
    }
}

注释写的都是很清楚,不用做过多的解释,关于计算每一个九宫格的中心点,就画图说明一下
这里写图片描述

图太难画了 ,我们首先减去了九宫格的直径,这样均分了之后,我们就可以得到每一个九宫格的最左边的点,然后用最左边的点加上了半径就得到了x方向的圆心。在y方向上同理。

MainActivity:

DrawPointLineUnlockView drawPointLineUnlockView = (DrawPointLineUnlockView) findViewById(R.id.lock);
        drawPointLineUnlockView.setOnDrawPointUnlockResultListener(new DrawPointLineUnlockView.OnDrawPointUnlockResultListener() {
            @Override
            public void onUnlock(String passward, boolean success) {
                Toast.makeText(MainActivity.this, passward, Toast.LENGTH_SHORT).show();
            }
        });

结尾

如果有什么问题和好的建议欢迎大家留言批评指正,尤其是妹纸。

作者:u011315960 发表于2016/11/18 20:34:22 原文链接
阅读:32 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>