React Native 中的 Gesture Responder System 和 PanResponder 探究

背景
移動設備上的各類點擊事件與web上徹底不同, 在web上,應用與用戶交互是經過鼠標,只能利用鼠標的單擊操做;而在移動設備上,是經過手勢系統,用戶是經過觸摸屏幕與應用交互的,這裏的狀況比web上要複雜不少,好比 App 須要判斷用戶的觸摸究竟是在滾動頁面,仍是滑動一個 widget,或者只是一個單純的點擊。甚至還有多點同時觸控的狀況。react

React Native 是經過 Gesture Responder System 來管理app中的手勢操做的整個生命週期的。git

如何響應用戶的觸摸事件
利用gesture responder system,一個View只須要要實現了一些定義好的方法,就能夠響應觸摸事件了:github

  • View.props.onStartShouldSetResponder: (evt) => true, - 在用戶開始觸摸的時候(手指剛剛接觸屏幕的瞬間),是否願意成爲響應者?
  • View.props.onMoveShouldSetResponder: (evt) => true, - 若是 View 不是響應者,那麼在每個觸摸點開始移動(沒有停下也沒有離開屏幕)時再詢問一次:是否願意響應觸摸交互呢?

若是 View 返回 true,並開始嘗試成爲響應者,那麼會觸發下列事件之一:web

  • View.props.onResponderGrant: (evt) => {} - View 如今要開始響應觸摸事件了。這也是須要作高亮的時候,使用戶知道他到底點到了哪裏。
  • View.props.onResponderReject: (evt) => {} - 響應者如今「另有其人」並且暫時不會「放權」,請另做安排。

若是 View 已經開始響應觸摸事件了,那麼下列這些處理函數會被一一調用:react-native

  • View.props.onResponderMove: (evt) => {} - 用戶正在屏幕上移動手指時(沒有停下也沒有離開屏幕)。
  • View.props.onResponderRelease: (evt) => {} - 觸摸操做結束時觸發,好比"touchUp"(手指擡起離開屏幕)。
  • View.props.onResponderTerminationRequest: (evt) => true - 有其餘組件請求接替響應者,當前的 View 是否「放權」?返回 true 的話則釋放響應者權力。
  • View.props.onResponderTerminate: (evt) => {} - 響應者權力已經交出。這多是因爲其餘 View 經過onResponderTerminationRequest請求的,也多是由操做系統強制奪權(好比 iOS 上的控制中心或是通知中心)。

手勢響應系統用起來可能比較複雜。因此RN利用了手勢響應系統封裝了一個抽象的Touchable實現(TouchableOpacity、TouchableHighlight等),用來作可觸控的組件,使得你能夠簡單地以聲明的方式來配置觸控處理。他們能夠綁定4種不一樣的響應方法app

  • onPress
  • onPressIn
  • onPressOut
  • onLonePress

而對於手指滑動(拖拽)、多點觸控等操做,利用上面的Touchable方法沒法實現,因而RN 又在手勢響應系統的基礎上封裝了一個 PanResponder 來處理更復雜的手勢操做。封裝後的PanResponder 方法的抽象程度更高,使用起來也更加方便:函數

panResponder = PanResponder.create({
    onStartShouldSetPanResponder: (evt, gestureState) => true,
    onMoveShouldSetPanResponder: (evt, gestureState) => true,
    onPanResponderGrant: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
    onPanResponderMove: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
    onPanResponderRelease: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
})
render() {
    <View style={styles.container}
        {...this.panResponder.panHandlers}
    > 
    ...
    </View>
}

PanResponder在手勢響應系統的原生事件以外提供了一個新的gestureState對象,提供了更多實用的字段(具體能夠看文檔);而且handler響應器回調函數是原來gesture responder system中的回調函數的增強版本:this

onMoveShouldSetPanResponder: (e, gestureState) => {...}
onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
onStartShouldSetPanResponder: (e, gestureState) => {...}
onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
onPanResponderReject: (e, gestureState) => {...}
onPanResponderGrant: (e, gestureState) => {...}
onPanResponderStart: (e, gestureState) => {...}
onPanResponderEnd: (e, gestureState) => {...}
onPanResponderRelease: (e, gestureState) => {...}
onPanResponderMove: (e, gestureState) => {...}
onPanResponderTerminate: (e, gestureState) => {...}
onPanResponderTerminationRequest: (e, gestureState) => {...}
onShouldBlockNativeResponder: (e, gestureState) => {...}
相關文章
相關標籤/搜索