跳到主內容

點選、拖動和其他手勢

在 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

指標已與螢幕接觸,並且可能開始水平或垂直移動。如果設定了 onHorizontalDragStartonVerticalDragStart,則此回撥會崩潰。

onPanUpdate

與螢幕接觸並正在垂直或水平方向上移動的指標。如果設定了 onHorizontalDragUpdateonVerticalDragUpdate,則此回撥會崩潰。

onPanEnd

先前與螢幕接觸的指標不再與螢幕接觸,並且在停止與螢幕接觸時以特定速度移動。如果設定了 onHorizontalDragEndonVerticalDragEnd,則此回撥會崩潰。

為小部件新增手勢檢測

#

要從小部件層級監聽手勢,請使用 GestureDetector

如果您正在使用 Material Components,許多這些小部件已經響應點選或手勢。例如,IconButtonTextButton 響應按下操作(點選),而 ListView 響應滑動以觸發滾動。如果您沒有使用這些小部件,但希望在點選時獲得“墨水飛濺”效果,可以使用 InkWell

手勢消歧

#

在螢幕上的給定位置,可能有多個手勢檢測器。例如

  • ListTile 具有響應整個 ListTile 的點選識別器,以及巢狀在尾部圖示按鈕周圍的一個識別器。尾部圖示的螢幕矩形現在被兩個需要協商誰處理手勢(如果碰巧是點選)的手勢識別器覆蓋。
  • 單個 GestureDetector 覆蓋螢幕區域,配置為處理多種手勢,例如長按和點選。tap 識別器現在必須與 long press 識別器協商,當用戶觸控式螢幕幕的該部分時。根據指標的後續操作,兩個識別器中的一個接收手勢,或者如果使用者執行既不是點選也不是長按的操作,則兩者都不接收手勢。

所有這些手勢檢測器都會監聽指標事件流,並嘗試識別特定的手勢。 GestureDetector 小部件會根據其哪些回撥不為空來決定嘗試識別哪些手勢。

當螢幕上存在多個手勢識別器時,框架透過讓每個識別器加入手勢競技場來消除歧義,以確定使用者打算使用哪個手勢。手勢競技場使用以下規則來確定哪個手勢獲勝

  • 任何時候,識別器都可以消除自身並離開競技場。如果競技場中只剩下一個識別器,則該識別器獲勝。

  • 任何時候,識別器都可以宣佈自己獲勝,導致所有剩餘識別器失敗。

例如,在消除水平和垂直拖動歧義時,當它們收到指標按下事件時,兩個識別器都會進入競技場。識別器會觀察指標移動事件。如果使用者水平移動指標超過一定數量的邏輯畫素,則水平識別器宣佈獲勝,手勢將被解釋為水平拖動。同樣,如果使用者垂直移動超過一定數量的邏輯畫素,則垂直識別器宣佈自己獲勝。

當只有一個水平(或垂直)拖動識別器時,手勢競技場是有益的。在這種情況下,競技場中只有一個識別器,並且水平拖動會立即被識別,這意味著水平移動的第一個畫素可以被視為拖動,並且使用者無需等待進一步的手勢消除歧義。