Flutter runApp GestureBinding使用介紹
GestureBinding介紹
在上一篇文章《Flutter runApp到渲染上屏》中,我們介紹了從runApp直到渲染到屏幕上.為了整體流程順暢因此一些內(nèi)容沒(méi)有花過(guò)多的文筆描述,所以本章節(jié)單獨(dú)陳述GestureBinding這個(gè)mixin對(duì)象.
想去了解一個(gè)類最好的方法無(wú)外乎去閱讀它的注釋,我們可以從它的注釋中去了解它是為了做什么,做了些什么, 能夠做什么.
原文 | 漢譯 |
---|---|
A binding for the gesture subsystem. ## Lifecycle of pointer events and the gesture arena ### [PointerDownEvent] When a [PointerDownEvent] is received by the [GestureBinding] (from [dart:ui.PlatformDispatcher.onPointerDataPacket], as interpreted by the [PointerEventConverter]), a [hitTest] is performed to determine which [HitTestTarget] nodes are affected. (Other bindings are expected to implement [hitTest] to defer to [HitTestable] objects. For example, the rendering layer defers to the [RenderView] and the rest of the render object hierarchy.) The affected nodes then are given the event to handle ([dispatchEvent] calls [HitTestTarget.handleEvent] for each affected node). If any have relevant [GestureRecognizer]s, they provide the event to them using [GestureRecognizer.addPointer]. This typically causes the recognizer to register with the [PointerRouter] to receive notifications regarding the pointer in question. Once the hit test and dispatching logic is complete, the event is then passed to the aforementioned [PointerRouter], which passes it to any objects that have registered interest in that event. Finally, the [gestureArena] is closed for the given pointer ([GestureArenaManager.close]), which begins the process of selecting a gesture to win that pointer. ### Other events A pointer that is [PointerEvent.down] may send further events, such as [PointerMoveEvent], [PointerUpEvent], or [PointerCancelEvent]. These are sent to the same [HitTestTarget] nodes as were found when the [PointerDownEvent] was received (even if they have since been disposed; it is the responsibility of those objects to be aware of that possibility). Then, the events are routed to any still-registered entrants in the [PointerRouter]'s table for that pointer. When a [PointerUpEvent] is received, the [GestureArenaManager.sweep] method is invoked to force the gesture arena logic to terminate if necessary. | 手勢(shì)子系統(tǒng)的綁定。 ## 指針事件和手勢(shì)競(jìng)技場(chǎng)的生命周期 ### [PointerDownEvent] 當(dāng) [GestureBinding] 接收到 [PointerDownEvent](來(lái)自[dart:ui.PlatformDispatcher.onPointerDataPacket],由[PointerEventConverter]), 執(zhí)行[hitTest]以確定哪個(gè)[HitTestTarget] 節(jié)點(diǎn)受到影響。 (其他Bindings預(yù)計(jì)實(shí)現(xiàn) [hitTest] 以推遲到 [HitTestable] 對(duì)象。例如,渲染層遵從 [RenderView] 和渲染對(duì)象的其余部分。) 然后給受影響的節(jié)點(diǎn)處理事件([dispatchEvent] 調(diào)用每個(gè)受影響節(jié)點(diǎn)的 [HitTestTarget.handleEvent])。如有相關(guān)[GestureRecognizer]s,他們使用[GestureRecognizer.addPointer]。這通常會(huì)導(dǎo)致識(shí)別器向 [PointerRouter] 注冊(cè)以接收有關(guān)有問(wèn)題的指針。 一旦命中測(cè)試和調(diào)度邏輯完成,事件就會(huì)發(fā)生傳遞給前面提到的 [PointerRouter],它將它傳遞給任何對(duì)象已經(jīng)注冊(cè)了對(duì)該事件的興趣。 最后,[gestureArena] 為給定的指針關(guān)閉([GestureArenaManager.close]),它開(kāi)始選擇一個(gè)贏得該指針的手勢(shì)。 ### 其他事件 [PointerEvent.down] 的指針可能會(huì)發(fā)送更多事件,例如[PointerMoveEvent]、[PointerUpEvent] 或 [PointerCancelEvent]。這些是發(fā)送到相同的 [HitTestTarget] 節(jié)點(diǎn) [PointerDownEvent] 已收到(即使它們已被處置;它是這些對(duì)象有責(zé)任意識(shí)到這種可能性)。 然后,事件被路由到[PointerRouter] 的指針表。 當(dāng)接收到 [PointerUpEvent] 時(shí),[GestureArenaManager.sweep] 方法被調(diào)用以強(qiáng)制手勢(shì)競(jìng)技場(chǎng)邏輯在必要時(shí)終止。 |
methods
了解完GestureBinding大致是做什么的, 我們?cè)倭私庖幌滤心男┓椒?
其中initInstances()不知道大家有沒(méi)有印象, 在BindingBase的構(gòu)造方法中有調(diào)用這個(gè)方法, 那自然在初始的時(shí)候會(huì)調(diào)用這個(gè)方法.
{ // 保存實(shí)例 _instance = this; // 平臺(tái)分發(fā), 這里接受native傳來(lái)的手勢(shì)信息作分發(fā) platformDispatcher.onPointerDataPacket = _handlePointerDataPacket; }
實(shí)際上也就是在開(kāi)始的時(shí)候注冊(cè)了手勢(shì)的接收分發(fā).那么手勢(shì)是如何分發(fā)的呢?我們不如看一下_handlePointerDataPacket 的具體實(shí)現(xiàn):
{ // 這里會(huì)將指針數(shù)據(jù)轉(zhuǎn)換為邏輯像素,同時(shí)保存 _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio)); // 首先,我們要了解下locked是從什么地方來(lái)的, // 可以看到它最終的改變地只有*lockEvents()*方法中,而*lockEvents()*方法 // 由*reassembleApplication()*或scheduleWarmUpFrame()調(diào)用, // 前者屬于例如熱重載之類時(shí)調(diào)用, 而后者我們?cè)趓unApp時(shí)也有過(guò)介紹. // 這里看起來(lái)更像是一個(gè)異步回調(diào)的鎖.也就是在重啟界面的時(shí)候不用去刷新指針隊(duì)列 if (!locked) _flushPointerEventQueue(); }
這里又引出來(lái)一個(gè)_flushPointerEventQueue()的概念,這里會(huì)真正的去分發(fā)手勢(shì)事件:
{ // 只有我們接收到了手勢(shì)隊(duì)列中還有對(duì)象就會(huì)持續(xù)運(yùn)行 while (_pendingPointerEvents.isNotEmpty){ // 這里刪除了第一個(gè)元素并返回第一個(gè)元素,也就是隊(duì)列的fifo. // 我們會(huì)依次處理接受到的手勢(shì)事件 handlePointerEvent(_pendingPointerEvents.removeFirst()); } }
那么,*handlePointerEvent()*做了什么呢?
// 斷言之類代碼已經(jīng)去掉 { // 如果這個(gè)開(kāi)關(guān)打開(kāi),我們可以獲取更平滑到手勢(shì)事件, // 比如90hz、120hz的屏幕. 我們?cè)谝恍┙缑嫣幚砩暇涂梢源蜷_(kāi)這個(gè)開(kāi)關(guān), // 同樣這個(gè)值也是可以動(dòng)態(tài)開(kāi)關(guān)的 if (resamplingEnabled) { // 重采樣這里不過(guò)多介紹,有興趣可以自行探索一下哦! _resampler.addOrDispatch(event); _resampler.sample(samplingOffset, _samplingClock); return; } _resampler.stop(); // 這里去處理指針事件,從名字上來(lái)看是非常迫切了,hhh _handlePointerEventImmediately(event); }
// 這里會(huì)對(duì)每一個(gè)指針事件進(jìn)行判斷,是否點(diǎn)中widget或者說(shuō)命中了哪個(gè)widget { HitTestResult? hitTestResult; if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent) { hitTestResult = HitTestResult(); hitTest(hitTestResult, event.position); if (event is PointerDownEvent) { _hitTests[event.pointer] = hitTestResult; } } else if (event is PointerUpEvent || event is PointerCancelEvent) { hitTestResult = _hitTests.remove(event.pointer); } else if (event.down) { hitTestResult = _hitTests[event.pointer]; } if (hitTestResult != null || event is PointerAddedEvent || event is PointerRemovedEvent) { dispatchEvent(event, hitTestResult); } }
這里的代碼比較簡(jiǎn)單, 如果事件是down、signal或者h(yuǎn)over之中的任何事件,則會(huì)通過(guò)hitTest()添加到HitTestResult中,假如是down事件還需要增加到_hitTests結(jié)果中.如果是up或者cancel事件,那說(shuō)明用戶取消了當(dāng)時(shí)到滑動(dòng)事件,我們自然而然需要去除相應(yīng)的事件.最后去分發(fā)手勢(shì).
void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) { if (hitTestResult == null) { try { // 分發(fā)指針時(shí), 會(huì)把所有通過(guò)條件的event都注冊(cè)到手勢(shì)路由里面 pointerRouter.route(event); } catch (exception, stack) { ... } return; } for (final HitTestEntry entry in hitTestResult.path) { try { // 這里回調(diào)一下結(jié)果判斷有沒(méi)有命中 entry.target.handleEvent(event.transformed(entry.transform), entry); } catch (exception, stack) { ... } } }
也就是到這里整體到流程就結(jié)束了.
總結(jié)
從源碼開(kāi)始帶著思考去跟蹤問(wèn)題, 也許問(wèn)題就很容易可以解決了.手勢(shì)的流程也就是在這一刻注冊(cè)的,
以上就是Flutter runApp GestureBinding使用介紹的詳細(xì)內(nèi)容,更多關(guān)于Flutter runApp GestureBinding的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android?Service基礎(chǔ)(啟動(dòng)服務(wù)與綁定服務(wù))
大家好,本篇文章主要講的是android?Service基礎(chǔ)(啟動(dòng)服務(wù)與綁定服務(wù)),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Android開(kāi)發(fā)之ProgressDialog進(jìn)度對(duì)話框用法示例
這篇文章主要介紹了Android開(kāi)發(fā)之ProgressDialog進(jìn)度對(duì)話框用法,簡(jiǎn)單介紹了ProgressDialog進(jìn)度對(duì)話框常見(jiàn)函數(shù)功能,并結(jié)合實(shí)例形式分析了ProgressDialog組件創(chuàng)建及使用進(jìn)度對(duì)話框相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android軟鍵盤(pán)狀態(tài)彈出與消失的示例
這篇文章主要介紹了本篇文章主要介紹了Android軟鍵盤(pán)狀態(tài)彈出與消失的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02Android中ProgressBar用法簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android中ProgressBar用法,以簡(jiǎn)單實(shí)例形式分析了Android中ProgressBar進(jìn)度條控件的功能與布局相關(guān)技巧,需要的朋友可以參考下2016-01-01Android中AlertDialog各種對(duì)話框的用法實(shí)例詳解
這篇文章主要介紹了Android中AlertDialog各種對(duì)話框的用法在項(xiàng)目開(kāi)發(fā)中經(jīng)常用的到,本文給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值2016-04-04Android、Flutter為不同的CPU架構(gòu)包打包APK(v7a、v8a、x86區(qū)別)
默認(rèn)情況下,Android和Flutter打包出來(lái)的Apk都是包含了所有架構(gòu)的,這樣打出來(lái)的apk體積相對(duì)于單架構(gòu)的apk有點(diǎn)大,這時(shí),我們就需要分別打出不同的架構(gòu)包2023-08-08Android中使用GridView實(shí)現(xiàn)仿微信圖片上傳功能(附源代碼)
由于工作要求最近在使用GridView完成圖片的批量上傳功能,我的例子當(dāng)中包含仿微信圖片上傳、拍照、本地選擇、相片裁剪等功能,如果有需要的朋友可以看一下2017-08-08Android入門(mén)之bindService的用法詳解
indService大家可以認(rèn)為它是和Android的一個(gè)共生體。即這個(gè)service所屬的activity如果消亡那么bindService也會(huì)消亡。本文將通過(guò)簡(jiǎn)單的例子帶大家了解一下bindService的用法,感興趣的可以了解一下2022-12-12Android 監(jiān)聽(tīng)鎖屏、解鎖、開(kāi)屏 功能代碼
這篇文章主要介紹了Android 監(jiān)聽(tīng)鎖屏、解鎖、開(kāi)屏 功能代碼的相關(guān)資料,需要的朋友可以參考下2016-06-06