手势响应系统
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
手势响应系统负责管理应用中手势的生命周期。一次触摸操作可能会经历多个阶段,应用需要识别用户的操作意图。例如,应用需要判断触摸是滚动操作、滑动控件还是点击操作。甚至在触摸持续期间,操作类型也可能发生变化。同时可能存在多个并发的触摸操作。
触摸响应系统让组件能够协调这些触摸交互,而无需了解其父组件或子组件的任何信息。
最佳实践
要让应用体验出色,每个操作都应具备以下特性:
-
反馈/高亮效果 - 向用户展示当前由哪个元素处理触摸,以及松开手势后会发生什么
-
可取消性 - 用户在执行操作时,应能通过将手指拖离来中途取消操作
这些特性让用户使用应用时更加舒适,因为它允许人们自由尝试和交互,无需担心操作失误。
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 => {}- 在触摸结束时触发,即"touchUp"事件 -
View.props.onResponderTerminationRequest: evt => true- 其他视图希望成为响应者。当前视图是否应释放响应权?返回 true 表示允许释放 -
View.props.onResponderTerminate: evt => {}- 响应权已从该视图移除。可能在调用onResponderTerminationRequest后被其他视图获取,也可能被操作系统不经询问直接获取(iOS 的控制中心/通知中心会出现这种情况)
evt 是一个合成触摸事件,结构如下:
nativeEventchangedTouches- 自上次事件以来发生变化的触摸事件数组identifier- 触摸标识符locationX- 触摸相对于元素的 X 坐标locationY- 触摸相对于元素的 Y 坐标pageX- 触摸相对于根元素的 X 坐标pageY- 触摸相对于根元素的 Y 坐标target- 接收触摸事件的元素节点 IDtimestamp- 触摸时间标识符,用于速度计算touches- 屏幕上当前所有触摸的数组
捕获 ShouldSet 处理程序
onStartShouldSetResponder 和 onMoveShouldSetResponder 采用冒泡模式调用,即从最深层节点开始。这意味着当多个视图的 *ShouldSetResponder 处理程序返回 true 时,最深层组件将成为响应者。这在大多数情况下是符合预期的,因为它确保了所有控件和按钮的可操作性。
但有时父组件需要确保自己成为响应者。这时可通过捕获阶段实现。在响应系统从最深层组件开始冒泡之前,会先执行捕获阶段并触发 on*ShouldSetResponderCapture 方法。因此若父视图需要在触摸开始时阻止子组件成为响应者,应设置返回 true 的 onStartShouldSetResponderCapture 处理程序。
-
View.props.onStartShouldSetResponderCapture: evt => true, -
View.props.onMoveShouldSetResponderCapture: evt => true,
PanResponder
如需进行更高级的手势解析,请参阅 PanResponder。