前端知識(shí) | React Native手勢(shì)響應(yīng)淺析

目前手機(jī)市場(chǎng)上邀泉,全面屏?xí)r代已經(jīng)勢(shì)不可擋买窟,為了增大屏幕,一個(gè)個(gè)物理按鍵已漸漸消失在手機(jī)上贾铝。那么隙轻,手勢(shì)將成為在移動(dòng)應(yīng)用開發(fā)中一個(gè)重要的組成部分,移動(dòng)設(shè)備上手勢(shì)識(shí)別要比 web 端復(fù)雜得多垢揩,往往用戶的一個(gè)手勢(shì)玖绿,我們?cè)?APP 上要通過好幾個(gè)階段去判斷用戶的真實(shí)意圖是什么,在 ReactNative (以下簡(jiǎn)稱 RN)中針對(duì)手勢(shì)處理也提供了從最基本的點(diǎn)擊手勢(shì)到復(fù)雜的滑動(dòng)等一系列解決方案叁巨,讓我們一起去看看斑匪。

RN基本觸控組件

RN 的組件除了 Text,其他組件默認(rèn)是不支持點(diǎn)擊事件的锋勺,也不能成為一個(gè)觸摸事件的響應(yīng)者蚀瘸。RN 提供了幾個(gè)比較直接的處理響應(yīng)事件的組件,基本上能滿足大部分的點(diǎn)擊事件的處理需求庶橱。

TouchableHighlight

TouchableNativeFeedback (僅限 Android 平臺(tái))

TouchableOpacity

TouchableWithoutFeedback


這幾個(gè)組件的功能和使用方法基本類似纳击,只是就 Touch 的效果反饋上有所差異徽级,他們有如下幾個(gè)回調(diào)方法:

onPressIn:用戶觸摸開始的時(shí)候底扳,也就是手指剛落在 Touch 點(diǎn)擊區(qū)域內(nèi)的時(shí)觸發(fā)

onPressOut:用戶觸摸結(jié)束的時(shí)候顾复,也就是手指從 Touch 點(diǎn)擊區(qū)域內(nèi)抬起的時(shí)觸發(fā)

onPress:用戶完成一次從 onPressIn 到 onPressOut 的過程,且時(shí)間很短枫绅,即一次快速點(diǎn)擊操作時(shí)觸發(fā)

onLongPress:用戶觸發(fā) onPressIn 且手指一段時(shí)間內(nèi)沒有抬起時(shí)觸發(fā)


這里以 TouchableHighlight 為例泉孩,貼一個(gè) Touch 的基本用法:

RN 中提供的 Touch 組件的使用非常簡(jiǎn)單,可以參考官方文檔撑瞧,這里就不做詳細(xì)的介紹了棵譬,我們主要來說下用戶的觸摸事件處理。


gesture responder system

在 RN 中预伺,響應(yīng)手勢(shì)的基本單位是 responder订咸,具體點(diǎn)說就是最常見的 View 組件。任何的 View 組件都可以成為一個(gè)手勢(shì)的響應(yīng)者酬诀。其實(shí)要把一個(gè)普通的 View 組件開發(fā)成為一個(gè)能響應(yīng)手勢(shì)操作的 responder 很簡(jiǎn)單脏嚷,話不多說,我們舉栗子瞒御!

乍一看父叙,WillMount 里面的這幾個(gè)方法名字又長(zhǎng)又奇怪,但是等你了解了 RN 手勢(shì)響應(yīng)的流程了之后肴裙,記憶這幾個(gè)方法就非常簡(jiǎn)單了趾唱。在我們探索這幾個(gè)方法之前,我們首先要記住一個(gè)重要的點(diǎn):

一個(gè) RN 應(yīng)用中只能存在一個(gè) responder蜻懦!

?一次正常的手勢(shì)操作的流程如下所示:

是否響應(yīng) Touch 或者 move 手勢(shì)->grant(被激活) ->move->release (結(jié)束事件)

與流程相對(duì)應(yīng)的方法是:

onStartShouldSetResponder(event) => true:在用戶開始進(jìn)行觸摸操作時(shí)(手指剛剛接觸屏幕的瞬間),詢問是否申請(qǐng)成為觸摸事件的響應(yīng)者甜癞,返回 true 為需要成為響應(yīng)者。

onMoveShouldSetResponder(event) => true:如果綁定的View不是響應(yīng)者宛乃,那么會(huì)在用戶的觸摸點(diǎn)開始移動(dòng)的時(shí)候再次詢問是否申請(qǐng)成為觸摸時(shí)間的響應(yīng)者悠咱,返回true

為需要成為響應(yīng)者。

假設(shè)組件通過上面的方法返回了 true征炼,表示發(fā)出了申請(qǐng)需要成為響應(yīng)者析既,但是我們前面說過,一個(gè) RN 應(yīng)用中只能有一個(gè) responder谆奥,那么接下來就需要協(xié)調(diào)所有組件的請(qǐng)求眼坏,看看這個(gè)響應(yīng)者的位置給誰。

onResponderGrant:(event) => {}:View 申請(qǐng)成功酸些,并成為了響應(yīng)者宰译。一般情況下,這時(shí)開始擂仍,組件進(jìn)入了激活狀態(tài)囤屹,并進(jìn)行一些事件處理或者手勢(shì)識(shí)別的初始化。

onResponderReject: (event) =>{}:View 申請(qǐng)失敗了逢渔,這就意味著有其他的組件正在成為或者已經(jīng)成為了響應(yīng)者肋坚,并且他不愿意交出這個(gè)權(quán)利。所以你被拒絕了~

如果你成為了響應(yīng)者肃廓,那么會(huì)收到后續(xù)的事件輸入并由你來決定他的行為動(dòng)作:

onResponderMove: (event) => 表示觸摸手指的移動(dòng)事件智厌,這個(gè)回調(diào)在一次完成的手勢(shì)動(dòng)作中可能會(huì)非常頻繁的調(diào)用,所以這個(gè)回調(diào)函數(shù)里面的內(nèi)容需要盡量簡(jiǎn)單

onResponderRelease: (event) => 表示觸摸完成盲赊,相當(dāng)于前面講的 Touch 里面的 onPressOut 方法铣鹏,表示用戶已經(jīng)完成了本次的觸摸操作,同時(shí)會(huì)釋放響應(yīng)者這個(gè)權(quán)利哀蘑。

在你成為響應(yīng)者期間诚卸,其他組件也有可能會(huì)申請(qǐng)成為響應(yīng)者葵第,那么此時(shí)RN會(huì)通過回調(diào)來詢問當(dāng)前的響應(yīng)者是否放權(quán)給其他申請(qǐng)者『夏纾回調(diào)如下:

onResponderTerminationRequest: (event) => true:如果我們返回的是 true卒密,那就代表當(dāng)前響應(yīng)者同意放權(quán),讓其他的組件來當(dāng)響應(yīng)者棠赛,自己回歸平淡的生活哮奇,同時(shí)也會(huì)回調(diào)一個(gè)函數(shù),通知組件事件響應(yīng)處理被終止了:

onResponderTerminate: (event) => {}:這個(gè)回調(diào)也會(huì)發(fā)生在系統(tǒng)直接終止組件的觸摸事件處理中睛约,比如用戶在進(jìn)行觸摸操作的時(shí)候鼎俘,來電話了,或者意外閃退了辩涝。

相信大家都發(fā)現(xiàn)了贸伐,所有的方法都有一個(gè) event 參數(shù),里面包含了一個(gè)觸摸事件數(shù)據(jù) nativeEvent膀值,nativeEvent 具體結(jié)構(gòu)如下圖:

chanedTouches:event 數(shù)組棍丐,從上次回調(diào)上報(bào)的觸摸事件,到這次上報(bào)之間的所有事件數(shù)組沧踏。因?yàn)樵谟脩粲|摸過程中會(huì)產(chǎn)生很多事件歌逢,有時(shí)候可能還沒來得及上報(bào),系統(tǒng)就用這種方式批量上報(bào)

identifier:觸摸的 ID翘狱,這個(gè) ID 存在周期為從觸摸開始到釋放為止秘案,主要是用來區(qū)別在多點(diǎn)觸控的情況下,區(qū)分是哪個(gè)手指的觸摸事件潦匈。

locationX 和 locationY:觸摸點(diǎn)相對(duì)于組件的位置

pageX 和 pageY:觸摸點(diǎn)相對(duì)于屏幕的位置

target:接收當(dāng)前觸摸事件的組件 ID

timestamp:當(dāng)前觸摸的事件的時(shí)間戳阱高,可以用來進(jìn)行滑動(dòng)的相關(guān)計(jì)算(速度,停留時(shí)長(zhǎng))

touches:event 數(shù)組茬缩,多點(diǎn)觸摸的時(shí)候赤惊,包含當(dāng)前所有觸摸點(diǎn)的事件


冒泡機(jī)制和事件捕獲

先前我們都是針對(duì)單一組件來說的,但是在實(shí)際開發(fā)過程中凰锡,我們往往會(huì)遇到很多嵌套之類的組件未舟,那如果在我們多重嵌套的組件中,每層組件綁定了一個(gè)手勢(shì)響應(yīng)且 onStartShouldSetResponder 或者 onMoveShouldSetResponder 回調(diào)都返回了 true 來申請(qǐng)成為響應(yīng)者的話掂为,又會(huì)怎么樣呢裕膀?我們舉個(gè)栗子來看看:


在這個(gè)大栗子中,我們嵌套了兩層組件勇哗,使得組件布局如圖:

在RN中昼扛,默認(rèn)情況下會(huì)遵循冒泡機(jī)制,也就是嵌套最深的組件最先開始響應(yīng)欲诺,那么我們栗子中的三層組件的 onStartShouldSetResponder 或者 onMoveShouldSetResponder 全部都返回 true 的情況下抄谐,那么 C 組件會(huì)優(yōu)先成為事件響應(yīng)者渺鹦。但在我們的實(shí)際開發(fā)中,可能你需要的是父組件去處理觸控事件斯稳,而禁止子組件響應(yīng)海铆,那腫么辦迹恐?挣惰。RN 給我們提供了一個(gè)事件捕獲機(jī)制,也就是在觸摸事件通過冒泡機(jī)制往下傳遞的時(shí)候殴边,先詢問上層有申請(qǐng)的組件是否捕獲該事件憎茂,不給子組件傳遞事件,即上面的栗子中锤岸,正常情況下通過冒泡機(jī)制竖幔,我們的觸控事件會(huì) A->B->C 這樣傳遞到 C 去響應(yīng)事件,當(dāng) A 傳遞到 B 時(shí)是偷,會(huì)詢問 A 是否捕獲這個(gè)觸控事件并且不再向下傳遞給 B 和 C拳氢,如果 A確認(rèn)捕獲,那么 A 即成為這個(gè)事件的響應(yīng)者蛋铆。具體的回調(diào)是:

onStartShouldSetResponderCapture: () => true :在觸摸事件開始的時(shí)候馋评,RN 容器的組件就會(huì)收到這么一個(gè)回調(diào)函數(shù),詢問是否捕獲事件成為響應(yīng)者刺啦,如果返回true留特,表示確認(rèn)捕獲事件

onMoveShouldSetResponderCapture: () =>true :在觸摸事件開始移動(dòng)的時(shí)候,再次詢問是否捕獲事件成為響應(yīng)者玛瘸,如果返回 true蜕青,表示確認(rèn)捕獲事件



PanResponder

除了 gesture responder system 之外,RN 還抽象出了一套 PanResponder 方法糊渊,這套方法的好處在于右核,使用起來更方便,在不改變?cè)械倪壿嫼土鞒痰那疤嵯旅烊蓿峁┝烁嗟膮?shù)贺喝,包含了手勢(shì)進(jìn)行過程中更多的信息,讓我們更好的去理解和處理用戶的手勢(shì)意圖芒篷,話不多說搜变,直接上栗子。


在上面的栗子中针炉,我們實(shí)現(xiàn)了在一個(gè)白色有邊框的事件響應(yīng)者開始響應(yīng)事件而變成綠色挠他,然后實(shí)現(xiàn)拖拽效果并且在拖拽過程中變成紅色,最后在釋放手指又變回白色的這么一個(gè)過程篡帕。


大體上和 gesture responder system 一樣殖侵,我們要注意的就是幾個(gè)方法的寫法加上了 Pan,并且?guī)讉€(gè)回調(diào)函數(shù)多了一個(gè) gesture 參數(shù)贸呢,他具體長(zhǎng)這樣的:

dx 和 dy:從觸摸操作開始到現(xiàn)在的累積橫向/縱向路程

moveX 和 moveY:最近一次移動(dòng)時(shí)的屏幕橫/縱坐標(biāo)

numberActiveTouches:當(dāng)前在屏幕上的有效觸摸點(diǎn)的數(shù)量

stated:和之前一樣,用來識(shí)別手指的ID

vx 和 vy:當(dāng)前橫向/縱向移動(dòng)的速度

x0 和 y0:當(dāng)觸摸操作開始時(shí)組件相對(duì)于屏幕的橫/縱坐標(biāo)


總結(jié)

以上是我對(duì) RN 的一些基礎(chǔ)學(xué)習(xí)和理解拢军,只舉了一些簡(jiǎn)單的栗子楞陷,要在項(xiàng)目里實(shí)現(xiàn)一些更為復(fù)雜的手勢(shì)操作,還需要進(jìn)一步的摸索研究茉唉。另外需要注意的是固蛾,上述的回調(diào)函數(shù)都是在 JS 線程中進(jìn)行的,可能會(huì)有些許延遲度陆。


【海說軟件接受各種技術(shù)咨詢及開發(fā)業(yè)務(wù)】

-END-?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艾凯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懂傀,更是在濱河造成了極大的恐慌趾诗,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹬蚁,死亡現(xiàn)場(chǎng)離奇詭異恃泪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)犀斋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門贝乎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闪水,你說我怎么就攤上這事糕非。” “怎么了球榆?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵朽肥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我持钉,道長(zhǎng)衡招,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任每强,我火速辦了婚禮始腾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘空执。我一直安慰自己浪箭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布辨绊。 她就那樣靜靜地躺著奶栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宣鄙,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天袍镀,我揣著相機(jī)與錄音,去河邊找鬼冻晤。 笑死苇羡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鼻弧。 我是一名探鬼主播设江,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼温数!你這毒婦竟也來了绣硝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤撑刺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后握玛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體够傍,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年挠铲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冕屯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拂苹,死狀恐怖安聘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓢棒,我是刑警寧澤浴韭,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站脯宿,受9級(jí)特大地震影響念颈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜连霉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一榴芳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跺撼,春花似錦窟感、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春谍夭,著一層夾襖步出監(jiān)牢的瞬間黑滴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工紧索, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袁辈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓珠漂,卻偏偏與公主長(zhǎng)得像晚缩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子媳危,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 觸控是移動(dòng)設(shè)備的核心功能荞彼,也移動(dòng)應(yīng)用交互的基礎(chǔ),Android 和 iOS 各自都有完善的觸摸事件處理機(jī)制待笑。Rea...
    reloadRen閱讀 4,295評(píng)論 0 53
  • 觸控是移動(dòng)設(shè)備的核心功能鸣皂,也移動(dòng)應(yīng)用交互的基礎(chǔ),Android 和 iOS 各自都有完善的觸摸事件處理機(jī)制暮蹂。Rea...
    街角仰望閱讀 4,541評(píng)論 0 2
  • React Native 進(jìn)階(一)--嵌入到Android原生應(yīng)用中棠枉、組件的生命周期浓体、顏色、圖片术健、觸摸事件 嵌入...
    呼呼哥閱讀 1,328評(píng)論 0 5
  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的汹碱?困惑于Cell怎么突然不能點(diǎn)擊了?糾結(jié)于如何實(shí)現(xiàn)這個(gè)奇葩響應(yīng)需求荞估?亦或是...
    Lotheve閱讀 57,338評(píng)論 51 599
  • 在iOS開發(fā)中經(jīng)常會(huì)涉及到觸摸事件咳促。本想自己總結(jié)一下,但是遇到了這篇文章勘伺,感覺總結(jié)的已經(jīng)很到位跪腹,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,026評(píng)論 4 26