點選、拖動和其他手勢
在 Flutter 中,點選和拖動等手勢的工作原理。
本文件解釋瞭如何在 Flutter 中監聽和響應手勢。手勢的例子包括點選、拖動和縮放。
Flutter 中的手勢系統具有兩個獨立的層級。第一層具有原始指標事件,這些事件描述了指標(例如觸控、滑鼠和觸控筆)在螢幕上的位置和移動。第二層具有手勢,這些手勢描述了語義操作,這些操作由一個或多個指標移動組成。
指標
#指標代表使用者與裝置螢幕互動的原始資料。有四種類型的指標事件
-
PointerDownEvent 指標已在特定位置與螢幕接觸。
-
PointerMoveEvent 指標已從螢幕上的一個位置移動到另一個位置。
-
PointerUpEvent 指標已停止與螢幕接觸。
-
PointerCancelEvent 來自此指標的輸入不再定向到此應用。
在指標按下時,框架會對您的應用執行命中測試,以確定指標與螢幕接觸的位置上存在哪個小部件。然後,指標按下事件(以及該指標的後續事件)將被分派到命中測試找到的最內層小部件。從那裡,事件會冒泡到樹中,並被分派到從最內層小部件到樹根路徑上的所有小部件。沒有機制可以取消或阻止指標事件進一步分派。
要直接從小部件層級監聽指標事件,請使用 Listener 小部件。但是,通常,請考慮使用手勢(如下所述)。
手勢
#手勢代表從多個單獨的指標事件(甚至多個單獨的指標)識別出的語義操作(例如,點選、拖動和縮放)。手勢可以分派多個事件,對應於手勢的生命週期(例如,拖動開始、拖動更新和拖動結束)。
點選
onTapDown-
可能導致點選的指標已在特定位置接觸螢幕。
onTapUp-
觸發點選的指標已在特定位置停止接觸螢幕。
onTap-
先前觸發
onTapDown的指標也觸發了onTapUp,最終導致了點選。 onTapCancel-
先前觸發
onTapDown的指標不會導致點選。
雙擊
onDoubleTap-
使用者在短時間內在螢幕上的相同位置點選了兩次。
長按
onLongPress-
指標在同一位置長時間保持與螢幕接觸。
垂直拖動
onVerticalDragStart-
指標已接觸螢幕並可能開始垂直移動。
onVerticalDragUpdate-
與螢幕接觸並垂直移動的指標已在垂直方向上移動。
onVerticalDragEnd-
之前與螢幕接觸並垂直移動的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。
水平拖動
onHorizontalDragStart-
指標已接觸螢幕並可能開始水平移動。
onHorizontalDragUpdate-
與螢幕接觸並水平移動的指標已在水平方向上移動。
onHorizontalDragEnd-
先前與螢幕接觸並水平移動的指標不再與螢幕接觸,並且在停止與螢幕接觸時以特定速度移動。
Pan
onPanStart-
指標已與螢幕接觸,並且可能開始水平或垂直移動。如果設定了
onHorizontalDragStart或onVerticalDragStart,則此回撥會崩潰。 onPanUpdate-
與螢幕接觸並正在垂直或水平方向上移動的指標。如果設定了
onHorizontalDragUpdate或onVerticalDragUpdate,則此回撥會崩潰。 onPanEnd-
先前與螢幕接觸的指標不再與螢幕接觸,並且在停止與螢幕接觸時以特定速度移動。如果設定了
onHorizontalDragEnd或onVerticalDragEnd,則此回撥會崩潰。
為小部件新增手勢檢測
#要從小部件層級監聽手勢,請使用 GestureDetector。
如果您正在使用 Material Components,許多這些小部件已經響應點選或手勢。例如,IconButton 和 TextButton 響應按下操作(點選),而 ListView 響應滑動以觸發滾動。如果您沒有使用這些小部件,但希望在點選時獲得“墨水飛濺”效果,可以使用 InkWell。
手勢消歧
#在螢幕上的給定位置,可能有多個手勢檢測器。例如
ListTile具有響應整個ListTile的點選識別器,以及巢狀在尾部圖示按鈕周圍的一個識別器。尾部圖示的螢幕矩形現在被兩個需要協商誰處理手勢(如果碰巧是點選)的手勢識別器覆蓋。- 單個
GestureDetector覆蓋螢幕區域,配置為處理多種手勢,例如長按和點選。tap識別器現在必須與long press識別器協商,當用戶觸控式螢幕幕的該部分時。根據指標的後續操作,兩個識別器中的一個接收手勢,或者如果使用者執行既不是點選也不是長按的操作,則兩者都不接收手勢。
所有這些手勢檢測器都會監聽指標事件流,並嘗試識別特定的手勢。 GestureDetector 小部件會根據其哪些回撥不為空來決定嘗試識別哪些手勢。
當螢幕上存在多個手勢識別器時,框架透過讓每個識別器加入手勢競技場來消除歧義,以確定使用者打算使用哪個手勢。手勢競技場使用以下規則來確定哪個手勢獲勝
-
任何時候,識別器都可以消除自身並離開競技場。如果競技場中只剩下一個識別器,則該識別器獲勝。
-
任何時候,識別器都可以宣佈自己獲勝,導致所有剩餘識別器失敗。
例如,在消除水平和垂直拖動歧義時,當它們收到指標按下事件時,兩個識別器都會進入競技場。識別器會觀察指標移動事件。如果使用者水平移動指標超過一定數量的邏輯畫素,則水平識別器宣佈獲勝,手勢將被解釋為水平拖動。同樣,如果使用者垂直移動超過一定數量的邏輯畫素,則垂直識別器宣佈自己獲勝。
當只有一個水平(或垂直)拖動識別器時,手勢競技場是有益的。在這種情況下,競技場中只有一個識別器,並且水平拖動會立即被識別,這意味著水平移動的第一個畫素可以被視為拖動,並且使用者無需等待進一步的手勢消除歧義。