第43章 React Native 手势响应器系统详解
Version: 0.77 手势响应器系统
手势响应器系统负责管理应用内手势的生命周期。应用需要判断用户意图,因此一次触摸可能经历多个阶段。例如,应用需区分用户是在滚动、滑动控件还是轻点。这种意图甚至可能在一次触摸持续期间发生变化,且屏幕上可能同时存在多个触摸点。
引入触摸响应器系统,是为了让组件能够协商触摸交互,而无需了解其父级或子组件的内部细节。
最佳实践
为了让应用体验出色,每个操作都应符合以下特性:
- 反馈/高亮:向用户展示当前是哪个元素在处理触摸,以及释放手势后会发生什么。 - 可取消性:在执行操作时,用户应能通过拖动手指离开来中途取消该操作。
这些特性能让用户在使用应用时更安心,允许他们大胆探索和交互,而不必担心犯错。
TouchableHighlight 和 Touchable*
响应器系统的直接使用较为复杂,因此我们为需要“可轻点”功能的场景提供了抽象的 Touchable 实现。它基于响应器系统,允许以声明式方式配置轻点交互。在任何原本会使用网页按钮或链接的地方,都可以使用 TouchableHighlight。
响应器生命周期
视图通过实现正确的协商方法成为触摸响应器。有两个方法用于询问视图是否愿意成为响应器:
- View.props.onStartShouldSetResponder: evt => true - 询问该视图在触摸开始时刻是否愿意成为响应器 - View.props.onMoveShouldSetResponder: evt => true - 当视图并非当前响应器时,每次触摸移动都会调用:询问该视图是否想“抢占”触摸响应权
如果视图返回 true 并尝试成为响应器,将出现以下两种结果之一:
- View.props.onResponderGrant: evt => {} - 视图已成为触摸事件的响应器。此时应进行高亮处理,向用户展示当前正在发生什么 - View.props.onResponderReject: evt => {} - 当前有别的对象是响应器,且不会释放该状态
当视图处于响应状态时,以下处理器可被调用:
- View.props.onResponderMove: evt => {} - 用户正在移动手指 - View.props.onResponderRelease: evt => {} - 触摸结束时触发,即“手指抬起” - View.props.onResponderTerminationRequest: evt => true - 有其他对象请求成为响应器:该视图应否释放响应器?返回 true 即允许释放 - View.props.onResponderTerminate: evt => {} - 响应器已从该视图被夺走。这可能发生在调用 onResponderTerminationRequest 后被其他视图接管,也可能由操作系统直接接管而不预先询问(例如在 iOS 上打开控制中心/通知中心时)
evt 是一个合成触摸事件,结构如下:
nativeEvent - changedTouches - 自上次事件以来发生变化的所有触摸事件数组 - identifier - 触摸事件的唯一 ID - locationX - 触摸点相对于该元素的 X 坐标 - locationY - 触摸点相对于该元素的 Y 坐标 - pageX - 触摸点相对于根元素的 X 坐标 - pageY - 触摸点相对于根元素的 Y 坐标 - target - 接收触摸事件的元素节点 ID - timestamp - 触摸时间标识,可用于速度计算 - touches - 当前屏幕上所有活跃触摸事件的数组
捕获阶段 ShouldSet 处理器
onStartShouldSetResponder 和 onMoveShouldSetResponder 采用冒泡模式调用,最深层节点最先被调用。这意味着当多个视图的 *ShouldSetResponder 处理器都返回 true 时,最深层的组件将成为响应器。这在大多数情况下是理想的,因为它确保了所有控件和按钮都可正常使用。
不过,有时父组件希望确保自身成为响应器。这可通过利用捕获阶段实现。在响应器系统从最深层组件向上冒泡之前,会先执行捕获阶段,触发 on*ShouldSetResponderCapture。因此,如果父视图想在触摸开始时阻止子视图成为响应器,它应提供一个返回 true 的 onStartShouldSetResponderCapture 处理器。
- View.props.onStartShouldSetResponderCapture: evt => true - View.props.onMoveShouldSetResponderCapture: evt => true
PanResponder
对于更高层次的手势解析,可查看 PanResponder。