在 iOS 中加速手势识别并解决手势冲突
status
category
date
summary
slug
icon
tags
password
随着应用场景越来越复杂,操作系统和 App 需要使用有限的操作形式实现尽可能多的功能,例如同一个按钮(既指 UIButton 也指实体硬件)需要分别实现单击、双击、长按等操作来对应不同的业务需求。但是为了适应普遍的大众习惯,各种操作在时间上的界限非常难定夺,例如单击之后多少毫秒内重复点击就算作双击,按住按钮多少毫秒才算长按等等。
为了满足多数用户,时间差一般定的比较大,因此前置操作的识别会让人感觉到卡顿。一些用户量很大的 App 也没能做到完美,例如抖音的播放界面可以单击暂停和双击喜欢,因为需要识别双击手势,单击暂停手势的识别显得非常缓慢,用户想暂停到特定画面变得非常困难。iOS 系统同样面临这个问题,虽然在辅助功能中已经添加了开关,用于调整连续点按速度的判断,但是仍然能够明显体会到差别,例如开启了钱包中“按两下侧边按钮”开关之后,按一下按钮锁屏时就会慢一拍。
本文以加速单击手势识别,并解决连续单击手势的冲突为例。为了找出具体是哪个手势识别比较“耗时”,可以先分别屏蔽除了单击外的其他手势,以观察单击手势的识别是否变快。比如发现屏蔽某个手势之后,单击识别得非常快,那么就要对这个手势开刀了。
另外在复杂场景中,识别多个手势的可能不是同一个控件,而是处在同一个触摸事件分发体系下的多个控件。事实上我们基本感受不到触摸事件传递的速度,因此只需要减小双击的有效时间间隔即可,如果能很快判断双击失效,就可以进行单击的事件传递了,所以为了简单,本文就以单个控件为例进行说明。
为了同时识别单击和双击手势,我们一般会写出如下代码:
这样是可以同时识别单击和双击手势的,不过双击手势的有效时间判断是系统默认的,因此单击时会出现文章开头提到的卡顿现象。为了解决这个问题,我们需要自定义一个 UITapGestureRecognizer,它能够设置双击识别的有效时间,声明:
实现:
将双击手势的类型从 UITapGestureRecognizer 更改为 UIShortTapGestureRecognizer,通过修改 UISHORT_TAP_MAX_DELAY 即可自定义双击的识别时间。这个时间太小会导致单击手势也识别失败,时间太大会造成单击时的响应迟钝,具体的数值需要结合业务和用户进行测试。
但是这样实现了之后发现一个问题,原本正常的连续点击现在最多只能识别双击了,之后的连续点击就会不断响应单击事件。拿抖音举例来说,修改前连续点击会触发连续的爱心动画,修改之后连续点击只会出现一次动画,从第三次开始每次点击都会触发播放或者暂停。原因很简单,上面的逻辑在进入多次连续点击之前是正确的,即在固定时间后异步检查 state,如果未识别则强制终止识别,但多次连续点击时正确的逻辑应该是:点击后立刻同步响应事件。
按照这个思路,我们需要一个值记录当前是否正在进行连续点击,并在识别成功和失败时分别更新这个值,这个值应当是私有的。同时我们应该暴露时间间隔属性,以方便复用和扩展,修改之后完整的代码声明:
实现:
参考:
Loading...