跳到主要內容

手勢回應器系統

手勢回應器系統管理應用程式中手勢的生命週期。當應用程式判斷使用者的意圖時,觸碰可能會經歷幾個階段。例如,應用程式需要判斷觸碰是滾動、在小工具上滑動還是點擊。這甚至可能在觸碰期間發生變化。也可能有多個同時發生的觸碰。

需要觸碰回應器系統,以允許組件協商這些觸碰互動,而無需了解其父組件或子組件的任何額外資訊。

最佳實務

為了讓您的應用程式感覺良好,每個動作都應具有以下屬性

  • 回饋/高亮顯示 - 向使用者顯示什麼正在處理他們的觸碰,以及當他們釋放手勢時會發生什麼
  • 可取消性 - 當執行動作時,使用者應該能夠透過將手指拖離來中止觸碰中的動作

這些功能讓使用者在使用應用程式時更加舒適,因為它允許人們在不害怕犯錯的情況下進行實驗和互動。

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 - 觸碰的 ID
    • locationX - 觸碰的 X 位置,相對於元素
    • locationY - 觸碰的 Y 位置,相對於元素
    • pageX - 觸碰的 X 位置,相對於根元素
    • pageY - 觸碰的 Y 位置,相對於根元素
    • target - 接收觸碰事件的元素的節點 ID
    • timestamp - 觸碰的時間識別碼,對於速度計算很有用
    • touches - 螢幕上所有目前觸碰的陣列

捕捉 ShouldSet 處理常式

onStartShouldSetResponderonMoveShouldSetResponder 以冒泡模式呼叫,其中最深層的節點首先被呼叫。這表示當多個視圖為 *ShouldSetResponder 處理常式傳回 true 時,最深層的組件將成為回應器。這在大多數情況下是理想的,因為它可以確保所有控制項和按鈕都可用。

但是,有時父組件會希望確保它成為回應器。這可以透過使用捕捉階段來處理。在回應器系統從最深層的組件冒泡之前,它會執行捕捉階段,觸發 on*ShouldSetResponderCapture。因此,如果父視圖想要防止子組件在觸碰開始時成為回應器,它應該有一個傳回 true 的 onStartShouldSetResponderCapture 處理常式。

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

PanResponder

對於更進階的手勢解譯,請查看PanResponder