Skip to main content

手势响应系统

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

¥The gesture responder system manages the lifecycle of gestures in your app. A touch can go through several phases as the app determines what the user's intention is. For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. This can even change during the duration of a touch. There can also be multiple simultaneous touches.

需要触摸响应器系统来允许组件协商这些触摸交互,而无需了解其父组件或子组件的任何其他信息。

¥The touch responder system is needed to allow components to negotiate these touch interactions without any additional knowledge about their parent or child components.

最佳实践

¥Best Practices

为了让你的应用感觉很棒,每个操作都应该具有以下属性:

¥To make your app feel great, every action should have the following attributes:

  • 反馈/高亮 - 向用户显示正在处理其触摸的内容,以及释放手势时会发生什么

    ¥Feedback/highlighting- show the user what is handling their touch, and what will happen when they release the gesture

  • 取消能力 - 进行操作时,用户应该能够通过将手指拖开来中止操作

    ¥Cancel-ability- when making an action, the user should be able to abort it mid-touch by dragging their finger away

这些功能使用户在使用应用时更加舒适,因为它允许人们进行实验和交互,而不必担心犯错误。

¥These features make users more comfortable while using an app, because it allows people to experiment and interact without fear of making mistakes.

可触摸高亮和可触摸*

¥TouchableHighlight and Touchable*

应答器系统使用起来可能很复杂。所以我们为应该是 "tappable" 的东西提供了一个抽象的 Touchable 实现。这使用响应程序系统并允许你以声明方式配置点击交互。在网络上任何需要使用按钮或链接的地方使用 TouchableHighlight

¥The responder system can be complicated to use. So we have provided an abstract Touchable implementation for things that should be "tappable". This uses the responder system and allows you to configure tap interactions declaratively. Use TouchableHighlight anywhere where you would use a button or link on web.

响应者生命周期

¥Responder Lifecycle

通过实现正确的协商方法,视图可以成为触摸响应者。有两种方法可以询问视图是否想成为响应者:

¥A view can become the touch responder by implementing the correct negotiation methods. There are two methods to ask the view if it wants to become responder:

  • View.props.onStartShouldSetResponder: evt => true, - 这个视图是否想在触摸开始时成为响应者?

    ¥View.props.onStartShouldSetResponder: evt => true, - Does this view want to become responder on the start of a touch?

  • View.props.onMoveShouldSetResponder: evt => true, - 当视图不是响应者时,调用视图上的每次触摸移动:此视图是否想要 "claim" 触摸响应能力?

    ¥View.props.onMoveShouldSetResponder: evt => true, - Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness?

如果视图返回 true 并尝试成为响应者,则会发生以下情况之一:

¥If the View returns true and attempts to become the responder, one of the following will happen:

  • View.props.onResponderGrant: evt => {} - 视图现在正在响应触摸事件。现在是高亮并向用户展示正在发生的事情的时候了

    ¥View.props.onResponderGrant: evt => {} - The View is now responding for touch events. This is the time to highlight and show the user what is happening

  • View.props.onResponderReject: evt => {} - 其他东西现在是响应者,不会释放它

    ¥View.props.onResponderReject: evt => {} - Something else is the responder right now and will not release it

如果视图有响应,则可以调用以下处理程序:

¥If the view is responding, the following handlers can be called:

  • View.props.onResponderMove: evt => {} - 用户正在移动手指

    ¥View.props.onResponderMove: evt => {} - The user is moving their finger

  • View.props.onResponderRelease: evt => {} - 在触摸结束时触发,即 "touchUp"

    ¥View.props.onResponderRelease: evt => {} - Fired at the end of the touch, ie "touchUp"

  • View.props.onResponderTerminationRequest: evt => true - 其他东西想成为响应者。这个视图应该释放响应者吗?返回 true 允许释放

    ¥View.props.onResponderTerminationRequest: evt => true - Something else wants to become responder. Should this view release the responder? Returning true allows release

  • View.props.onResponderTerminate: evt => {} - 响应者已从视图中移除。可能会在调用 onResponderTerminationRequest 后被其他视图获取,或者可能会在没有询问的情况下被操作系统获取(iOS 上的控制中心/通知中心会发生这种情况)

    ¥View.props.onResponderTerminate: evt => {} - The responder has been taken from the View. Might be taken by other views after a call to onResponderTerminationRequest, or might be taken by the OS without asking (happens with control center/ notification center on iOS)

evt 是一个合成触摸事件,其形式如下:

¥evt is a synthetic touch event with the following form:

  • nativeEvent

    • changedTouches - 自上次事件以来发生更改的所有触摸事件的数组

      ¥changedTouches - Array of all touch events that have changed since the last event

    • identifier - 触摸的 ID

      ¥identifier - The ID of the touch

    • locationX - 触摸相对于元素的 X 位置

      ¥locationX - The X position of the touch, relative to the element

    • locationY - 触摸相对于元素的 Y 位置

      ¥locationY - The Y position of the touch, relative to the element

    • pageX - 触摸的 X 位置,相对于根元素

      ¥pageX - The X position of the touch, relative to the root element

    • pageY - 触摸的 Y 位置,相对于根元素

      ¥pageY - The Y position of the touch, relative to the root element

    • target - 接收触摸事件的元素的节点 id

      ¥target - The node id of the element receiving the touch event

    • timestamp - 触摸的时间标识符,对于速度计算很有用

      ¥timestamp - A time identifier for the touch, useful for velocity calculation

    • touches - 屏幕上当前所有触摸的数组

      ¥touches - Array of all current touches on the screen

捕获 ShouldSet 处理程序

¥Capture ShouldSet Handlers

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

¥onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, where the deepest node is called first. That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers. This is desirable in most cases, because it makes sure all controls and buttons are usable.

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

¥However, sometimes a parent will want to make sure that it becomes responder. This can be handled by using the capture phase. Before the responder system bubbles up from the deepest component, it will do a capture phase, firing on*ShouldSetResponderCapture. So if a parent View wants to prevent the child from becoming responder on a touch start, it should have a onStartShouldSetResponderCapture handler which returns true.

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

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

PanResponder

对于更高级别的手势解释,请查看 PanResponder

¥For higher-level gesture interpretation, check out PanResponder.