react-native ScrollView触摸与滚动事件
2017-08-29 16:51
513 查看
ScrollView是我们常用的组件之一,因此搞清楚它的触摸与滚动事件十分重要!
(1)onStartShouldSetResponderCapture
这个属性接收一个回调函数,函数原型是 function(evt): bool,在触摸事件开始(touchDown)的时候,RN 容器组件会回调此函数,询问组件是否要劫持事件响应者设置,自己接收事件处理,如果返回 true,表示需要劫持;
也就是说,我们在触碰ScrollView的时候,这个方法是第一个调用的,目的是判断是否进行劫持这个触摸事件(true是拦截,不让子视图去处理触摸事件;false是放开,交给子视图处理本次触摸事件)。目前,这个方法里面只对两种情况进行了处理,一是,屏幕内是否有TextInput正处于focused状态,如果是,则拦截,交给ScrollView去处理(例如:我们在ScrollView里面使用了TextInput,而此时正处于focused状态,我们点击ScrollView的其他区域则响应的应该是滑动事件);二是,判断现在动画是否正在进行(true是正在进行,false是没有正在进行的动画)。
注意:如果将这个函数的返回值,一直保持的是true,那么所有的触摸事件将不会下发给子视图,也就是说只可以响应ScrollView的触摸与滚动事件。
(2)onStartShouldSetResponder
这个属性接收一个回调函数,函数原型是 function(evt): bool,在触摸事件开始(touchDown)的时候,RN 会回调此函数,询问组件是否需要成为事件响应者,接收事件处理,如果返回 true,表示需要成为响应者;
假如组件通过上面的方法返回了 true,表示发出了申请要成为事件响应者请求,想要接收后续的事件输入。因为同一时刻,只能有一个事件处理响应者,RN 还需要协调所有组件的事件处理请求,所以不是每个组件申请都能成功,RN 通过如下两个回调来通知告诉组件它的申请结果。也就是说,只是去询问你想不想成为事件响应者,具体能不能成功,要看下面函数。
这个方法全部返回false,在这个地方基本没起到作用,因为轻触一下屏幕还不足以让它成为事件响应者(毕竟主要功能是滚动),看注释的意思是后期扩展使用!
(3)onTouchStart
按下屏幕时触发,即使现在屏幕还在滚动或者有其他手指又触发屏幕。
(4)onTouchEnd
手指离开屏幕触摸结束时触发,即使现在屏幕还在滚动,跟onTouchStart相反。
(1)onTouchMove
移动手指时触发,表示触摸手指移动的事件,这个回调可能非常频繁,所以这个回调函数的内容需要尽量简单;可以观察一下,这个过程中一共触发两轮onTouchMove方法,第一轮,指的是手指发生了小范围的移动,但是不足以触发屏幕滚动;第二轮,是真正的视图滚动。总之,只要手指发生偏移量,这个方法就会被回调。
(2)onScrollBeginDr
4000
ag
拖拽开始,子视图开始移动,只是开始时回去调用。
(3)onScrollShouldSetResponder
跟前面onStartShouldSetResponder相类似,询问组件是否需要成为滚动事件响应者,接收事件处理,如果返回 true,表示需要成为响应者;
isTouching指的是当前ScrollView区域是否还有触摸点。
(4)onResponderGrant
表示申请成功,组件成为了事件处理响应者,这时组件就开始接收后序的滚动事件输入。一般情况下,这时开始,组件进入了激活状态,并进行一些事件处理或者手势识别的初始化。
(5)onScroll(_handleScroll)
也许在这些方法中,我们最关心,也是最容易使用到的就是在这个方法了。像平时我们需要ScrollView的滑动来操作某些动画或者其他情况的,依靠的就是这个方法。
注意:注释部分人家也说了,如果你没有设置scrollEventThrottle这个属性,那么onScroll这个方法只是回调一次,如果设置的16(js:60帧每秒,每帧大概16ms),那么会引起丢帧的问题,总之选一个合适的值。
手指释放后,视图成为响应者,释放滚动事件。
(2)onScrollEndDrag
滑动结束拖拽时触发,并不一定是停止滚动。
(3)onMomentumScrollBegin
接着就是一帧滚动的开始onMomentumScrollBegin,它的起始位置和onScrollEndDrag的结束位置重合。(惯性滚动)
(4)onScrollShouldSetResponder
因为这个时候,所有手指全部抬起来了,所以返回值一直就是false,则ScrollView不想成为滚动事件响应者,更不存在下面的那些流程了。
(5)onScroll(_handleScroll)
滚动并没有停止,坐标一直在变化,所以还会回调。
注:设置scrollEventThrottle这个属性,onScrollShouldSetResponder和onScroll频繁回调。
(6)onMomentumScrollEnd
最后是一帧滚动的结束,惯性滚动结束,屏幕静止。
1.在ScrollView里面轻触一下
(1)onStartShouldSetResponderCapture
这个属性接收一个回调函数,函数原型是 function(evt): bool,在触摸事件开始(touchDown)的时候,RN 容器组件会回调此函数,询问组件是否要劫持事件响应者设置,自己接收事件处理,如果返回 true,表示需要劫持;
/** * There are times when the scroll view wants to become the responder * (meaning respond to the next immediate `touchStart/touchEnd`), in a way * that *doesn't* give priority to nested views (hence the capture phase): * * - Currently animating. * - Tapping anywhere that is not the focused input, while the keyboard is * up (which should dismiss the keyboard). * * Invoke this from an `onStartShouldSetResponderCapture` event. */ scrollResponderHandleStartShouldSetResponderCapture: function(e: Event): boolean { // First see if we want to eat taps while the keyboard is up var currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); if (!this.props.keyboardShouldPersistTaps && currentlyFocusedTextInput != null && e.target !== currentlyFocusedTextInput) { return true; } return this.scrollResponderIsAnimating(); },
也就是说,我们在触碰ScrollView的时候,这个方法是第一个调用的,目的是判断是否进行劫持这个触摸事件(true是拦截,不让子视图去处理触摸事件;false是放开,交给子视图处理本次触摸事件)。目前,这个方法里面只对两种情况进行了处理,一是,屏幕内是否有TextInput正处于focused状态,如果是,则拦截,交给ScrollView去处理(例如:我们在ScrollView里面使用了TextInput,而此时正处于focused状态,我们点击ScrollView的其他区域则响应的应该是滑动事件);二是,判断现在动画是否正在进行(true是正在进行,false是没有正在进行的动画)。
注意:如果将这个函数的返回值,一直保持的是true,那么所有的触摸事件将不会下发给子视图,也就是说只可以响应ScrollView的触摸与滚动事件。
(2)onStartShouldSetResponder
这个属性接收一个回调函数,函数原型是 function(evt): bool,在触摸事件开始(touchDown)的时候,RN 会回调此函数,询问组件是否需要成为事件响应者,接收事件处理,如果返回 true,表示需要成为响应者;
假如组件通过上面的方法返回了 true,表示发出了申请要成为事件响应者请求,想要接收后续的事件输入。因为同一时刻,只能有一个事件处理响应者,RN 还需要协调所有组件的事件处理请求,所以不是每个组件申请都能成功,RN 通过如下两个回调来通知告诉组件它的申请结果。也就是说,只是去询问你想不想成为事件响应者,具体能不能成功,要看下面函数。
/** * Merely touch starting is not sufficient for a scroll view to become the * responder. Being the "responder" means that the very next touch move/end * event will result in an action/movement. * * Invoke this from an `onStartShouldSetResponder` event. * * `onStartShouldSetResponder` is used when the next move/end will trigger * some UI movement/action, but when you want to yield priority to views * nested inside of the view. * * There may be some cases where scroll views actually should return `true` * from `onStartShouldSetResponder`: Any time we are detecting a standard tap * that gives priority to nested views. * * - If a single tap on the scroll view triggers an action such as * recentering a map style view yet wants to give priority to interaction * views inside (such as dropped pins or labels), then we would return true * from this method when there is a single touch. * * - Similar to the previous case, if a two finger "tap" should trigger a * zoom, we would check the `touches` count, and if `>= 2`, we would return * true. * */ scrollResponderHandleStartShouldSetResponder: function(): boolean { return false; },
这个方法全部返回false,在这个地方基本没起到作用,因为轻触一下屏幕还不足以让它成为事件响应者(毕竟主要功能是滚动),看注释的意思是后期扩展使用!
(3)onTouchStart
按下屏幕时触发,即使现在屏幕还在滚动或者有其他手指又触发屏幕。
(4)onTouchEnd
手指离开屏幕触摸结束时触发,即使现在屏幕还在滚动,跟onTouchStart相反。
2.滚动ScrollView
手指抬起之前
前面散步已经说过了,就不过多介绍了。(1)onTouchMove
移动手指时触发,表示触摸手指移动的事件,这个回调可能非常频繁,所以这个回调函数的内容需要尽量简单;可以观察一下,这个过程中一共触发两轮onTouchMove方法,第一轮,指的是手指发生了小范围的移动,但是不足以触发屏幕滚动;第二轮,是真正的视图滚动。总之,只要手指发生偏移量,这个方法就会被回调。
(2)onScrollBeginDr
4000
ag
拖拽开始,子视图开始移动,只是开始时回去调用。
(3)onScrollShouldSetResponder
跟前面onStartShouldSetResponder相类似,询问组件是否需要成为滚动事件响应者,接收事件处理,如果返回 true,表示需要成为响应者;
/** * Invoke this from an `onScroll` event. */ scrollResponderHandleScrollShouldSetResponder: function(): boolean { return this.state.isTouching; },
isTouching指的是当前ScrollView区域是否还有触摸点。
(4)onResponderGrant
表示申请成功,组件成为了事件处理响应者,这时组件就开始接收后序的滚动事件输入。一般情况下,这时开始,组件进入了激活状态,并进行一些事件处理或者手势识别的初始化。
(5)onScroll(_handleScroll)
也许在这些方法中,我们最关心,也是最容易使用到的就是在这个方法了。像平时我们需要ScrollView的滑动来操作某些动画或者其他情况的,依靠的就是这个方法。
_handleScroll: function(e: Object) { console.log('***********_handleScroll'); if (__DEV__) { if (this.props.onScroll && !this.props.scrollEventThrottle && Platform.OS === 'ios') { console.log( // eslint-disable-line no-console-disallow 'You specified `onScroll` on a <ScrollView> but not ' + '`scrollEventThrottle`. You will only receive one event. ' + 'Using `16` you get all the events but be aware that it may ' + 'cause frame drops, use a bigger number if you don\'t need as ' + 'much precision.' ); } } if (Platform.OS === 'android') { if (this.props.keyboardDismissMode === 'on-drag') { dismissKeyboard(); } } this.scrollResponderHandleScroll(e); },
注意:注释部分人家也说了,如果你没有设置scrollEventThrottle这个属性,那么onScroll这个方法只是回调一次,如果设置的16(js:60帧每秒,每帧大概16ms),那么会引起丢帧的问题,总之选一个合适的值。
手指抬起之后(红框里面)
(1)onResponderRelease手指释放后,视图成为响应者,释放滚动事件。
(2)onScrollEndDrag
滑动结束拖拽时触发,并不一定是停止滚动。
(3)onMomentumScrollBegin
接着就是一帧滚动的开始onMomentumScrollBegin,它的起始位置和onScrollEndDrag的结束位置重合。(惯性滚动)
(4)onScrollShouldSetResponder
因为这个时候,所有手指全部抬起来了,所以返回值一直就是false,则ScrollView不想成为滚动事件响应者,更不存在下面的那些流程了。
(5)onScroll(_handleScroll)
滚动并没有停止,坐标一直在变化,所以还会回调。
注:设置scrollEventThrottle这个属性,onScrollShouldSetResponder和onScroll频繁回调。
(6)onMomentumScrollEnd
最后是一帧滚动的结束,惯性滚动结束,屏幕静止。
未完待续(事件抢夺)
相关文章推荐
- react native scrollview深入详解触摸滚动事件
- react native scrollview深入详解触摸滚动事件
- react native scrollview 滚动停止事件
- React Native scrollview滚动事件
- react-native scrollView 中部分有用事件
- react native ScrollView滚动不起作用
- React Native 之 Using a ScrollView
- React Native 触摸事件处理详解
- React Native - pointerEvent属性介绍(当前视图是否处理触摸事件)
- 解决NestedScrollView中,在子View上滑动不触发滚动事件,却触发点击事件
- react native ScrollView 使用详解
- React Native Android ScrollView 去除阴影效果
- React Native ScrollView 添加图片数组
- ReactNative中处理触摸事件
- React Native 触摸事件处理详解
- React Native WebView 内点击事件获取onNavigationStateChange、onMessage
- 【React Native开发】- 触摸事件处理
- 解决android中HorizontalScrollView的滚动事件与组件的Touch冲突问题
- React Native WebView 内点击事件获取onNavigationStateChange、onMessage
- iOS的手势事件和可滚动视图(tableView、collectionView...)的触摸事件冲突的解决方法