手势响应系统
手势响应系统管理应用程序中手势的生命周期。当应用程序确定用户的意图时,触摸可以经历多个阶段。例如,应用程序需要确定触摸是滚动、在小部件上滑动还是点击。这甚至可以在触摸持续时间内发生变化。还可以有多个同时触摸。
触摸响应系统是为了允许组件协商这些触摸交互而无需任何关于其父或子组件的额外知识。
最佳实践
为了使您的应用感觉良好,每个操作都应具有以下属性
- 反馈/突出显示 - 向用户显示正在处理其触摸的内容,以及释放手势后会发生什么
- 可取消性 - 在执行操作时,用户应该能够通过将手指拖离来在触摸过程中中止操作
这些功能使用户在使用应用程序时更加舒适,因为它允许人们进行实验和交互而无需担心出错。
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
是一个具有以下形式的合成触摸事件
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。