前言
九宫格手势解锁已经是非常常见的手机解锁方式,支付宝等一些软件也都曾经使用过,感觉还是很高大上的。在github已经有很好的开源控件,大家可以去自己搜索,我自己写了一个自定义的九宫格控件,作为练习作业。
效果图##
我不会做动图,就凑合看吧......
先贴自定义属性代码`
`复制代码
我把自定义属性的连线宽度,作为了九宫格的实心圆的半径和外面的空心圆的边框宽度。
贴代码
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. ** 九宫格解锁View *
* 可以定制颜色和九宫格的数量 */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
pointsList; /** * 已经绘制的九宫格的点 */ private ArrayList drawPoints; /** * 进行判断的点 * * 只创建一个,不返回的创建对象,节省内存 */ 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方向上同理。
贴出DrawPoint的代码:
package lzp.com.interestlibrary.view.bean;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.PointF;/** * Created by li.zhipeng on 16/11/18. ** 九宫格的点 */public class DrawPoint extends PointF { /** * 外部的空心圆的半径 */ private int pointRadius; /** * 内部的小实心圆的半径 */ private int centerPointRadius; /** * 这个点的值,用于解锁密码的匹配 */ private int value; public int getValue(){ return value; } public DrawPoint(int value, int pointRadius, int centerPointRadius) { this.value = value; this.pointRadius = pointRadius; this.centerPointRadius = centerPointRadius; } public void draw(Canvas canvas, Paint paint) { // 画中心的小实心圆 paint.setStyle(Paint.Style.FILL); canvas.drawCircle(x, y, centerPointRadius, paint); // 画外面的空心圆 paint.setStyle(Paint.Style.STROKE); canvas.drawCircle(x, y, pointRadius, paint); } /** * 重写此方法,判断是否包含这个点 */ @Override public boolean equals(Object o) { if (o instanceof DrawPoint) { // 匹配的误差是 大圆的半径 DrawPoint point = (DrawPoint) o; if (Math.abs(this.x - point.x) < pointRadius && Math.abs(this.y - point.y) < pointRadius) { return true; } } return false; }}复制代码
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(); } });复制代码
##结尾##
如果有什么问题和好的建议欢迎大家留言批评指正,尤其是妹纸。