手势响应系统
手势响应系统管理应用中手势的生命周期。触摸可以经历多个阶段,因为应用需要确定用户的意图。例如,应用需要确定触摸是滚动、在小部件上滑动还是轻点。这甚至可以在触摸持续期间发生变化。还可以存在多个同时发生的触摸。
需要触摸响应系统来允许组件协商这些触摸交互,而无需了解其父组件或子组件的任何额外信息。
最佳实践
为了让您的应用体验更好,每个操作都应具有以下属性
- 反馈/高亮——向用户展示什么正在处理他们的触摸,以及当他们释放手势时会发生什么
- 可取消性——在执行操作时,用户应该能够通过将手指拖离来在中途中止它
这些功能让用户在使用应用时更舒适,因为它允许人们在不担心出错的情况下进行实验和交互。
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
- 触摸的 IDlocationX
- 触摸的 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。