跳到主要内容

手势响应系统

手势响应系统管理应用中手势的生命周期。当应用确定用户的意图时,一次触摸会经历多个阶段。例如,应用需要确定触摸是滚动、在小部件上滑动还是点击。这甚至可能在触摸的持续时间内发生变化。也可能存在多个同时触摸。

需要触摸响应系统来允许组件在不了解其父组件或子组件的任何额外信息的情况下协商这些触摸交互。

最佳实践

为了让您的应用感觉良好,每个操作都应具有以下属性:

  • 反馈/高亮显示 - 向用户展示什么正在处理他们的触摸,以及当他们释放手势时会发生什么
  • 可取消性 - 执行操作时,用户应该可以通过将手指拖离来在触摸中途中止操作

这些功能让用户在使用应用程序时更舒适,因为它们允许人们实验和互动,而不用担心犯错。

TouchableHighlight 和 Touchable*

响应系统可能很复杂。因此,我们为应该“可点击”的事物提供了一个抽象的 Touchable 实现。这使用响应系统并允许您以声明方式配置点击交互。在任何您会在 Web 上使用按钮或链接的地方使用 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 处理程序

onStartShouldSetResponderonMoveShouldSetResponder 以冒泡模式调用,其中最深的节点首先被调用。这意味着当多个视图对 *ShouldSetResponder 处理程序返回 true 时,最深的组件将成为响应器。在大多数情况下,这是可取的,因为它确保所有控件和按钮都可用。

然而,有时父级会希望确保它成为响应器。这可以通过使用捕获阶段来处理。在响应系统从最深层组件冒泡之前,它将执行一个捕获阶段,触发 on*ShouldSetResponderCapture。因此,如果父级视图希望阻止子级在触摸开始时成为响应器,它应该有一个返回 true 的 onStartShouldSetResponderCapture 处理程序。

  • View.props.onStartShouldSetResponderCapture: evt => true,
  • View.props.onMoveShouldSetResponderCapture: evt => true,

PanResponder

有关更高级别的手势解释,请查看 PanResponder