本文件解釋瞭如何在 Flutter 中監聽和響應_手勢_。手勢的例子包括輕觸、拖動和縮放。

Flutter 中的手勢系統有兩個獨立的層。第一層是原始指標事件,描述了指標(例如,觸控、滑鼠和觸控筆)在螢幕上的位置和移動。第二層是_手勢_,描述了由一個或多個指標移動組成語義操作。

指標

#

指標代表使用者與裝置螢幕互動的原始資料。有四種類型的指標事件

PointerDownEvent
指標在特定位置接觸螢幕。
PointerMoveEvent
指標已從螢幕上的一個位置移動到另一個位置。
PointerUpEvent
指標已停止接觸螢幕。
PointerCancelEvent
此指標的輸入不再指向此應用。

在指標按下時,框架會對您的應用進行_命中測試_,以確定指標接觸螢幕的位置存在哪個小部件。然後,指標按下事件(以及該指標的後續事件)將分派給命中測試找到的最內部小部件。從那裡,事件沿著樹向上冒泡,並分派給從最內部小部件到樹根路徑上的所有小部件。沒有取消或停止指標事件進一步分派的機制。

要直接從小部件層監聽指標事件,請使用 Listener 小部件。但是,通常情況下,請考慮使用手勢(如下所述)代替。

手勢

#

手勢表示語義操作(例如,輕觸、拖動和縮放),這些操作是從多個單獨的指標事件中識別出來的,甚至可能是多個單獨的指標。手勢可以分派多個事件,對應於手勢的生命週期(例如,拖動開始、拖動更新和拖動結束)

點選

onTapDown
可能導致點選的指標已在特定位置接觸螢幕。
onTapUp
觸發點選的指標已在特定位置停止接觸螢幕。
onTap
之前觸發 onTapDown 的指標也觸發了 onTapUp,最終導致了一次輕觸。
onTapCancel
之前觸發 onTapDown 的指標最終不會導致輕觸。

雙擊

onDoubleTap
使用者在同一位置快速連續輕觸螢幕兩次。

長按

onLongPress
指標在同一位置長時間保持與螢幕接觸。

垂直拖動

onVerticalDragStart
指標已接觸螢幕並可能開始垂直移動。
onVerticalDragUpdate
一個接觸螢幕並垂直移動的指標已在垂直方向移動。
onVerticalDragEnd
之前與螢幕接觸並垂直移動的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。

水平拖動

onHorizontalDragStart
指標已接觸螢幕並可能開始水平移動。
onHorizontalDragUpdate
一個接觸螢幕並水平移動的指標已在水平方向移動。
onHorizontalDragEnd
一個之前接觸螢幕並水平移動的指標不再接觸螢幕,並在停止接觸螢幕時以特定速度移動。

平移

onPanStart
指標已接觸螢幕並可能開始水平或垂直移動。如果設定了 onHorizontalDragStartonVerticalDragStart,此回撥將崩潰。
onPanUpdate
一個接觸螢幕並在垂直或水平方向移動的指標。如果設定了 onHorizontalDragUpdateonVerticalDragUpdate,此回撥將崩潰。
onPanEnd
一個之前接觸螢幕的指標不再接觸螢幕,並在停止接觸螢幕時以特定速度移動。如果設定了 onHorizontalDragEndonVerticalDragEnd,此回撥將崩潰。

為小部件新增手勢檢測

#

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

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

手勢消歧

#

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

  • 一個 ListTile 有一個響應整個 ListTile 的輕觸識別器,以及一個圍繞尾部圖示按鈕的巢狀識別器。尾部圖示的螢幕區域現在被兩個手勢識別器覆蓋,如果手勢最終被識別為輕觸,它們需要協商由誰來處理。
  • 一個 GestureDetector 覆蓋了一個配置為處理多個手勢(例如長按和輕觸)的螢幕區域。當用戶觸控式螢幕幕的該部分時,輕觸識別器現在必須與 長按識別器協商。根據該指標接下來發生的情況,兩個識別器之一會接收到手勢,或者如果使用者執行的既不是輕觸也不是長按的操作,則兩個識別器都不會接收到手勢。

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

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

  • 在任何時候,識別器都可以自行退出競技場。如果競技場中只剩下一個識別器,該識別器獲勝。

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

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

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