點擊、拖曳和其他手勢
本文件說明如何在 Flutter 中監聽並回應手勢。手勢的範例包括點擊、拖曳和縮放。
Flutter 中的手勢系統有兩個不同的層。第一層具有原始指標事件,描述指標 (例如觸摸、滑鼠和手寫筆) 在螢幕上的位置和移動。第二層具有手勢,描述由一個或多個指標移動組成的語義動作。
指標
#指標代表使用者與裝置螢幕互動的原始資料。指標事件有四種類型
PointerDownEvent
- 指標已在特定位置接觸螢幕。
PointerMoveEvent
- 指標已從螢幕上的一個位置移動到另一個位置。
PointerUpEvent
- 指標已停止接觸螢幕。
指標取消事件 (PointerCancelEvent)
- 來自此指標的輸入不再導向此應用程式。
當指標按下時,框架會對您的應用程式執行命中測試,以確定螢幕上指標接觸位置存在哪個 Widget。然後,指標按下事件(以及該指標的後續事件)會被派發到命中測試找到的最內層 Widget。從那裡,事件會向上冒泡至樹狀結構,並被派發到從最內層 Widget 到樹狀結構根目錄路徑上的所有 Widget。沒有任何機制可以取消或停止指標事件的進一步派發。
若要直接從 Widget 層監聽指標事件,請使用 Listener
Widget。然而,一般來說,請考慮改用手勢(如下所述)。
手勢
#手勢代表從多個單獨的指標事件(甚至可能是多個單獨的指標)中識別出的語義動作(例如,點擊、拖曳和縮放)。手勢可以派發多個事件,對應於手勢的生命週期(例如,拖曳開始、拖曳更新和拖曳結束)。
點擊
onTapDown
- 一個可能導致點擊的指標已在特定位置接觸螢幕。
onTapUp
- 觸發點擊的指標已停止在特定位置接觸螢幕。
onTap
- 先前觸發
onTapDown
的指標也觸發了onTapUp
,最終導致點擊。 onTapCancel
- 先前觸發
onTapDown
的指標不會導致點擊。
雙擊
onDoubleTap
- 使用者已在同一個位置快速連續點擊螢幕兩次。
長按
onLongPress
- 一個指標在同一個位置與螢幕保持接觸一段長時間。
垂直拖曳
onVerticalDragStart
- 一個指標已接觸螢幕,並且可能會開始垂直移動。
onVerticalDragUpdate
- 一個與螢幕接觸並垂直移動的指標已在垂直方向上移動。
onVerticalDragEnd
- 一個先前與螢幕接觸並垂直移動的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。
水平拖曳
onHorizontalDragStart
- 一個指標已接觸螢幕,並且可能會開始水平移動。
onHorizontalDragUpdate
- 一個與螢幕接觸並水平移動的指標已在水平方向上移動。
onHorizontalDragEnd
- 一個先前與螢幕接觸並水平移動的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。
平移
onPanStart
- 一個指標已接觸螢幕,並且可能會開始水平或垂直移動。如果設定了
onHorizontalDragStart
或onVerticalDragStart
,則此回呼會崩潰。 onPanUpdate
- 一個與螢幕接觸並在垂直或水平方向上移動的指標。如果設定了
onHorizontalDragUpdate
或onVerticalDragUpdate
,則此回呼會崩潰。 onPanEnd
- 一個先前與螢幕接觸的指標不再與螢幕接觸,並且在停止接觸螢幕時以特定速度移動。如果設定了
onHorizontalDragEnd
或onVerticalDragEnd
,則此回呼會崩潰。
將手勢偵測新增至 Widget
#若要從 Widget 層監聽手勢,請使用 GestureDetector
。
如果您使用的是 Material Components,則其中許多 Widget 已會回應點擊或手勢。例如,IconButton
和 TextButton
會回應按下(點擊),而 ListView
會回應滑動以觸發捲動。如果您未使用這些 Widget,但想要點擊時出現「墨水濺射」效果,則可以使用 InkWell
。
手勢消除歧義
#在螢幕上的特定位置,可能有多個手勢偵測器。例如
- 一個
ListTile
有一個回應整個ListTile
的點擊辨識器,以及一個巢狀的點擊辨識器在尾端圖示按鈕周圍。尾端圖示的螢幕矩形現在被兩個手勢辨識器覆蓋,如果最終是點擊,它們需要協商由誰處理手勢。 - 單個
GestureDetector
涵蓋一個螢幕區域,該螢幕區域配置為處理多個手勢,例如長按和點擊。當使用者觸摸螢幕的該部分時,tap
辨識器現在必須與long press
辨識器協商。根據該指標接下來發生的情況,兩個辨識器中的一個會接收到手勢,或者如果使用者執行既不是點擊也不是長按的操作,則兩個辨識器都不會接收到手勢。
所有這些手勢偵測器都會監聽流經的指標事件串流,並嘗試辨識特定的手勢。GestureDetector
Widget 會根據其哪些回呼不是 null 來決定要嘗試辨識哪些手勢。
當螢幕上給定指標有多個手勢辨識器時,框架會讓每個辨識器加入手勢競技場來消除使用者意圖的歧義。手勢競技場使用以下規則確定哪個手勢獲勝
任何時候,辨識器都可以自行淘汰並離開競技場。如果競技場中只剩一個辨識器,則該辨識器獲勝。
任何時候,辨識器都可以宣告自己獲勝,導致所有剩餘的辨識器失敗。
例如,在消除水平和垂直拖曳的歧義時,當它們接收到指標按下事件時,兩個辨識器都會進入競技場。辨識器會觀察指標移動事件。如果使用者將指標水平移動超過一定數量的邏輯像素,則水平辨識器會宣告勝利,並且該手勢被解釋為水平拖曳。同樣地,如果使用者垂直移動超過一定數量的邏輯像素,則垂直辨識器會宣告自己獲勝。
當只有水平(或垂直)拖曳辨識器時,手勢競技場會很有幫助。在這種情況下,競技場中只有一個辨識器,並且會立即辨識水平拖曳,這表示水平移動的第一個像素可以被視為拖曳,而使用者不需要等待進一步的手勢消除歧義。
除非另有說明,否則本網站上的文件反映了 Flutter 的最新穩定版本。頁面上次更新於 2024-07-06。 查看原始碼 或 回報問題。