手勢識別在移動設(shè)備上比在網(wǎng)絡(luò)上要復(fù)雜得多。當(dāng)應(yīng)用程序確定用戶的意圖時(shí),一個(gè)觸摸可能要經(jīng)歷幾個(gè)階段。例如,應(yīng)用程序需要確定觸摸是否是滾動,滑動部件還是輕擊。這甚至可以在觸摸期間發(fā)生改變,也可以有多個(gè)同時(shí)觸摸。
要想使組件在沒有任何額外的關(guān)于它們的父組件或子組件的知識的情況下處理這些觸摸交互,需要觸摸應(yīng)答系統(tǒng)。這個(gè)系統(tǒng)在 ResponderEventPlugin.js
中實(shí)現(xiàn)了,其中包含更多細(xì)節(jié)和文檔。
用戶在 web 應(yīng)用程序與本機(jī)的可用性上可以感覺到巨大的差異,并且這是最大的原因之一。每一個(gè)動作都應(yīng)該有以下屬性:
反饋/高亮——顯示給用戶是什么正在處理他們的觸摸,以及當(dāng)他們釋放手勢時(shí),會發(fā)生什么
撤銷的能力——當(dāng)做一個(gè)動作時(shí),用戶應(yīng)該能夠在觸摸過程中通過移動手指中止該動作。
這些特性讓用戶使用一個(gè)應(yīng)用程序時(shí)更舒適,因?yàn)樗试S人們在實(shí)驗(yàn)和交互時(shí)不用擔(dān)心犯錯(cuò)誤。
應(yīng)答系統(tǒng)在使用時(shí)可能是復(fù)雜的。所以我們?yōu)閼?yīng)該“可以輕擊的”東西提供了一個(gè)抽象的 Touchable
實(shí)現(xiàn)。這使用了應(yīng)答系統(tǒng),并且使你以聲明的方式可以輕松地識別輕擊交互。在網(wǎng)絡(luò)中任何你會用到按鈕或鏈接的地方使用TouchableHighlight
。
通過實(shí)施正確的處理方法,視圖可以成為接觸應(yīng)答器。有兩種方法來詢問視圖是否想成為應(yīng)答器:
View.props.onStartShouldSetResponder: (evt) => true,
——這個(gè)視圖是否在觸摸開始時(shí)想成為應(yīng)答器?
View.props.onMoveShouldSetResponder: (evt) => true,
——當(dāng)視圖不是應(yīng)答器時(shí),該指令被在視圖上移動的觸摸調(diào)用:這個(gè)視圖想“聲明”觸摸響應(yīng)嗎?
如果視圖返回 true 并且想成為應(yīng)答器,那么下述的一種情況就會發(fā)生:
View.props.onResponderGrant:(evt)= > { }
——視圖現(xiàn)在正在響應(yīng)觸摸事件。這個(gè)時(shí)候要高亮標(biāo)明并顯示給用戶正在發(fā)生的事情。
View.props.onResponderReject:(evt)= > { }
——其他的東西時(shí)應(yīng)答器并且不會釋放它。
如果視圖正在響應(yīng),那么可以調(diào)用以下處理程序:
View.props.onResponderMove:(evt)= > { }
——用戶正移動他們的手指
View.props.onResponderRelease:(evt)= > { }
——在觸摸最后被引發(fā),即“touchUp”
View.props.onResponderTerminationRequest:(evt)= >true
——其他的東西想成為應(yīng)答器。這種視圖應(yīng)該釋放應(yīng)答嗎?返回 true 就是允許釋放
View.props.onResponderTerminate:(evt)= > { }
——應(yīng)答器已經(jīng)從視圖獲取了??赡茉谡{(diào)用onResponderTerminationRequest
之后被其他視圖獲取,也可能是被操作系統(tǒng)在沒有請求的情況下獲取了(發(fā)生在 iOS 的 control center/notification center)
evt
是一個(gè)綜合的觸摸事件,有以下形式:
nativeEvent
changedTouches
——自從上個(gè)事件之后,所有發(fā)生改變的觸摸事件的數(shù)組
identifier
——觸摸的 ID
locationX
——觸摸相對于元素的 X 位置
locationY
——觸摸相對于元素的 Y 位置
pageX
——觸摸相對于屏幕的 X 位置
pageY
——觸摸相對于屏幕的 Y 位置
target
——接收觸摸事件的元素的節(jié)點(diǎn) id
timestamp
——觸摸的時(shí)間標(biāo)識符,用于速度計(jì)算
touches
——所有當(dāng)前在屏幕上觸摸的數(shù)組
在冒泡模式,即最深的節(jié)點(diǎn)最先被調(diào)用,的情況下,onStartShouldSetResponder
和 onMoveShouldSetResponder
被調(diào)用。這意味著,當(dāng)多個(gè)視圖為 * ShouldSetResponder
處理程序返回 true 時(shí),最深的組件會成為應(yīng)答器。在大多數(shù)情況下,這是可取的,因?yàn)樗_保了所有控件和按鈕是可用的。
然而,有時(shí)父組件會想要確保它成為應(yīng)答器。這可以通過使用捕獲階段進(jìn)行處理。在應(yīng)答系統(tǒng)從最深的組件冒泡時(shí),它將進(jìn)行一個(gè)捕獲階段,引發(fā) * ShouldSetResponderCapture
。所以如果一個(gè)父視圖要防止子視圖在觸摸開始時(shí)成為應(yīng)答器,它應(yīng)該有一個(gè) onStartShouldSetResponderCapture
處理程序,返回 true。
View.props.onStartShouldSetResponderCapture: (evt) => true,
View.props.onMoveShouldSetResponderCapture: (evt) => true,
更多建議: