1. 前言
2. LockPoint实体
- 每个点是一个实体(LockPoint)用来存储这个点的所有信息,包括点的物理位置(x,y)和点的index位置(0-8)
1 | class LockPoint { |
3. 初始化
- 初始化九个点的位置,需要根据控件的大小动态计算,因此在onMeare()之后进行
- 需求是需要将九个点放在控件中间,来适应控件大小的变化,首先确定第一个点距离左边的距离startSpace,两个点之间的距离 =(控件宽度 - 2 * startSpace)/2
1 | int size = getMeasuredWidth(); |
- 初始化九个点的位置
1 | // 初始化九个点的位置 |
- onMeasure()完整代码
1 | // onMeasure之后初始化数据 |
4. onDraw
绘制过程大致分为三个步骤
<1> 绘制九个点,这是每次都需要绘制的 1>
1 | LockPoint tempPoint; |
- <2> 绘制已经划过的点2>
1 | // 绘制之前触过存储起来的的点,绘制第i个点和i+1个点之间的线 |
- <3> 绘制触摸点和最后一个点的连线3>
1 | // 画最后一个点和触摸的点之间的线 |
5. 事件处理
- 对用户touch事件进行处理
- 要记录当前触摸的点,用于绘制跟随手指的连线
- 检测触摸的点是不是在九个点中某个点的范围内,如果是的话该点要加入被触摸点的列表中
- 当手指抬起时,清除数据,恢复初始状态
1 |
|
6. 优化-多点触控事件处理
- 用户在触摸屏幕时可能有多个手指在操作,上面的代码在单指时没有问题,兼容多点触控的思路是:
- 当用户触发down事件时,我们可以获取到一个pointerId,这个id唯一的标志了这个指头,后面发生的所有事件都使用用这个pointerId来获取,只处理这个指头的事件,避免事件的错乱。
- 当我们开始的时候标志的那个手指抬起来了怎么办呢,两个解决方法,第一个就是直接结束整个流程,相当于单指时手指抬起。第二个方法就是转移事件,当一个指头抬起时,从该事件中获取还没抬起的手指,更改标志的pointerId,事件就转移到了另一个手指上,我们关心就是新手指的触摸啦
- 关于对于事件进行处理的相关机制可以看Android事件机制,写的都是比较基本的东西,后面慢慢完善,不过理解获取多指的事件9⃣️绰绰有余啦
- 话不多说,上代码,比较需要注意的地方我都标注在注释中,方便查找
1 | // 处理触摸事件,支持多点触摸 |
- 转移焦点的方法,在各种控件的源代码中随处可见,我也是拷贝出来直接用的,逻辑不是很复杂
1 | /** |
- 发布结果
1 | /** |
- 回复初始状态,因为在多处调用了,贴一下
1 | /** |
7. 优化-自动添加两点之间连线上的点
当滑动时越过中间的点之间连接两端,自动查找和添加两点之间的点,手机上的滑动解锁也是这样的逻辑,不然会导致图形很繁琐,不美观而且不符合常见逻辑。也就是说如果当前激发的点和上一个激发的点之间有没有激发的点,那么自动给他激发。
首先如果两个点是相邻的或者是对角线上相邻,那么中间一定不会有空下来的点,需要排除这个情况
1 |
|
- 然后如何判断一个点位于首尾两个激发点的中间,思路是当这个点在两个点的连线上时且不是首尾两个点就是中间的点。判断的根据是斜率是不是相等,就是初中的数学问题啦。
1 | /** |
- 最后整合一下,去掉不必要的判断,在touch事件中调用
1 | /** |
- 在onTouchEvent中调用
1 | LockPoint centerPoint = findCenterPoint(tempPoint); |
8. 优化-给被触摸的点添加动画
当手指触摸到一个点时,添加一个缩放动画来反馈触摸操作
思路时,当触摸到一个点时使用ValueAnimator开启动画,不断改变半径的值,在绘制时达到实现缩放的效果
1 | /** |
- 同时在onDraw()方法中对刚刚触摸的点要进行绘制,更改onDraw()方法中绘制九个点的部分,对刚刚触摸的点使用缩放后的半径绘制。
1 | // 绘制九个点,当动画在执行时被激活的点会被放大 |
9. 回调
- 使用监听将结果回调给使用者,在ACTION_UP时发布结果
1 | public interface OnLockFinishListener { |
10. 综上
- 还遗留了一个点,就是自动添加中间的点时应该也是有动画效果的,暂时还没做,有空补上吧,希望大家指正。
11. 完整代码
1 | /** |