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