ReactNative觸摸事件處理
對RN觸摸事件的捕獲與冒泡機制的理解
組件A、B、C結構
組件A
組件B
組件C
捕獲、冒泡機制
sequenceDiagram
A->>A: 是否捕獲?若是則停止向下一級傳遞
A->>B:
B->>B: 是否捕獲?若是則停止向下一級傳遞
B->>C:
C->>C: 是否捕獲?若是則停止向下一級傳遞
C->>C: 是否聲明成為響應者?無論是否,都冒泡。
C->>B:
B->>B: 是否聲明成為響應者?無論是否,都冒泡。
B->>A:
A->>A: 是否聲明成為響應者?
捕獲期可通過onStartShouldSetResponderCapture 或 onMoveShouldSetResponderCapture回調決定是否阻止事件往下級組件傳遞。
冒泡期可通過onStartShouldSetResponder或onMoveShouldSetPanResponder回調決定是否成為響應者。若上級組件與下級組件都返回true,則下級組件成為當前觸摸事件的響應者。(層級越深的組件優先級越高)
補充:
RN如何處理觸摸事件
View組件的pointerEvents屬性
用於控制當前視圖是否可以作為觸控事件的目標。
- auto:視圖可以作為觸控事件的目標。
- none:視圖不能作為觸控事件的目標。
- box-none:視圖自身不能作為觸控事件的目標,但其子視圖可以。
View組件可用的手勢
onTouchStart={()=>console.log('start')}
onTouchMove={()=>console.log('move')}
onTouchEnd={()=>console.log('end')}
PanResponder 手勢監視器
// 創建監視器
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: ()=>{},
...
})
// 在View中使用
<View
{...this.panResponder}
/>
事件參數
每個事件都有兩個返回參數nativeEvent, gestureState
nativeEvent包含以下屬性
changedTouches - 在上一次事件之后,所有發生變化的觸摸事件的數組集合(即上一次事件后,所有移動過的觸摸點)
identifier - 觸摸點的 ID
locationX - 觸摸點相對於父元素的橫坐標(實踐證明不好用,值會突變!原因未知)
locationY - 觸摸點相對於父元素的縱坐標(實踐證明不好用,值會突變!)
pageX - 觸摸點相對於根元素的橫坐標
pageY - 觸摸點相對於根元素的縱坐標
target - 觸摸點所在的元素 ID
timestamp - 觸摸事件的時間戳,可用於移動速度的計算
touches - 當前屏幕上的所有觸摸點的集合
gestureState包含以下屬性:
stateID 此次觸摸事件的ID
moveX 最近一次移動的屏幕坐標
moveY
x0 響應器產生時的屏幕坐標(手勢第一個坐標)
y0
dx 觸摸開始累積的橫向路程
dy
vx 當前的橫向移動速度
vy
numberActiveTouches 觸摸點數量
事件生命周期
單點事件
onStartShouldSetResponderCapture 如果父視圖想要阻止子視圖響應 touch start 事件,它就應該設置這個方法並返回 true。
onStartShouldSetResponder 在用戶開始觸摸的時候(手指剛剛接觸屏幕的瞬間),返回是否願意成為響應者
onPanResponderGrant 這個視圖開始響應觸摸事件。此時需要高亮告訴用戶正在響應。
onPanResponderStart 觸摸事件正式被監視
onPanResponderEnd 觸摸事件結束
onPanResponderRelease 在整個觸摸事件結束時調用這個函數。
移動事件
onMoveShouldSetResponderCapture 如果父視圖想要阻止子視圖響應 touch move 事件時,它就應該設置這個方法並返回 true
onMoveShouldSetPanResponder 這個視圖想要“認領”這個 touch move 事件嗎?每當有 touch move 事件在這個視圖中發生,並且這個視圖沒有被設置為這個 touch move 的響應時,這個函數就會被調用。
onPanResponderGrant 監視器發出通知開始工作
onPanResponderMove 當用戶正在屏幕上移動手指時調用這個函數。
異常事件
onPanResponderReject 有一個響應器正處於活躍狀態,並且不會向另一個要求響應這個事件的視圖釋放這個事件。
onPanResponderTerminationRequest 其他某個視圖想要成為事件的響應者,並要求這個視圖放棄對事件的響應時,就會調用這個函數。如果允許釋放響應,就返回true。
onPanResponderTermination 響應被從這個視圖上“劫走”了。可能是在調用了 onResponderTerminationRequest 之后,被另一個視圖“劫走”了(見 onresponderterminationrequest), 也可能是由於 OS 無條件終止了響應(比如說被 iOS 上的控制中心/消息中心)