0%

【文章翻譯】Material Range Slider in Flutter

【文章內容使用 Gemini 1.5 Pro 自動產生】

Flutter 中的 Material RangeSlider

範圍滑桿是 Flutter 1.7 中釋出的高度自訂元件,用於選擇一組值。本文說明了範圍滑桿是什麼,為什麼您可能需要使用它,以及如何使用 Material 主題自訂 Flutter RangeSlider 的行為和外觀。

為什麼要使用範圍滑桿?

滑桿元件可以提供單一選取或多重選取,在離散或連續軌道上。與單一選取滑桿不同的是,單一選取滑桿預先確定最小值或最大值,並且可以在一個方向上調整選取,範圍滑桿具有兩個選取點,允許靈活調整最小值和最大值點。這種靈活性使其成為有用的元件,適用於使用者希望控制特定範圍的情況,例如指示價格點或時間長度。

結構和實作

RangeSlider 由 5 個部分組成:

  1. 一個軌道,拇指可以在上面滑動。
  2. 當 RangeSlider 為離散時,軌道上的刻度線。
  3. 2 個拇指(或旋鈕),表示範圍的最小值和最大值。
  4. 值指示器,在定義標籤且 showValueIndicator 與滑桿類型相符時,顯示拇指值的標籤。
  5. 當拇指被按下時,顯示在拇指上的覆蓋層。

我們需要 RangeSlider 具有豐富的動畫。這包括拇指位置的互動驅動動畫,以及覆蓋層和值指示器的內建動畫。在 Flutter 中,我們透過將 RangeSlider 元件設為 StatefulWidget 來做到這一點,它將動畫控制器作為狀態儲存。

實際的範圍滑桿值會儲存在父 Widget 中的狀態。透過在 RangeSlider 的 onChange() 回呼函數中呼叫 setState() 來更新值。換句話說,為了擁有互動式範圍滑桿,RangeSlider Widget 本身必須在 StatefulWidget 中建立。

RangeSlider 的 State 物件會構建 LeafRenderObjectWidget。所有內容都繪製在它的內部 RenderBox 中,它也處理觸控輸入。

處理觸控輸入

如果您好奇 RangeSlider 如何實作觸控輸入,請繼續閱讀!RangeSlider 的一個有趣之處在於,它是少數使用 GestureArenaTeam 的原生 Flutter Widget 之一。下一節將說明如何自訂觸控輸入。

如果您不感興趣,請跳過此節。

為了確保 RangeSlider 可以處理點擊和拖曳,同時在捲軸視圖、標籤列視圖和其他處理手勢的 Widget 中正常運作,會使用 GestureArenaTeam。GestureArenaTeam 允許透過「獲勝」來正確選擇一組手勢中的手勢。

首先,將拖曳辨識器加入到團隊中,然後加入點擊辨識器。沒有團隊隊長,因此一旦任何其他辨識器退出競技場,拖曳辨識器就會獲勝,因為它是第一個加入團隊的辨識器。另一方面,如果點擊可以直接獲勝,例如當滑桿在垂直捲軸列表中,使用者點擊然後立即鬆開時,則點擊辨識器會獲勝。

拖曳和點擊事件會解析為 3 種可能的互動之一:

  • 拖曳 onStart 或點擊 onTapDown → _startInteraction
  • 拖曳 onUpdate → _handleDragUpdate
  • 拖曳 onEnd 或 onCancel 以及點擊 onEnd 或 onCancel → _endInteraction

在互動開始時,必須確定的第一件事之一是哪個拇指應該被選取以進行移動。RangeSlider 透過使用可主題化函數來做到這一點,該函數會接收點擊值和拖曳位移等屬性,並返回拇指選擇:Thumb.start、Thumb.end 或 null(表示沒有選取)。

預設拇指選擇器首先嘗試在 _startInteraction 中找到最接近的拇指。如果選取了一個拇指,則拇指的位置會立即更新為點擊值。但是,如果點擊值位於拇指之間,但不在任何觸控目標中,則不會選取任何拇指。此外,如果拇指彼此足夠接近,並且點擊位於兩個觸控目標中,則不會選取任何拇指。在這種情況下,只有在存在非零移動(拖曳位移)時才會選取拇指。然後,對於負移動會選取左邊拇指,對於正移動會選取右邊拇指。這是唯一一種互動實際上在第一個 _handleDragUpdate 步驟中開始的情況。無論哪種情況,一個特殊的回呼函數 onChangeStart() 都會發出此互動的開始值。

當拇指分開較遠時,觸控內部軌道不會選取拇指:

當拇指更加靠近時,會使用拖曳位移來確定拇指選擇:

實作具有上述行為的預設拇指選擇器:

選取拇指後,所有未來的拖曳更新都用於確定拇指的新位置。覆蓋層動畫從選取的拇指開始,值指示器動畫從兩個拇指開始。當使用者拖曳選取的拇指時,範圍滑桿會發出一組帶有更新位置的新值,然後這些值會傳回範圍滑桿,以更新其對應的位置。

最後一步是 _endInteraction。一旦點擊或拖曳手勢抬起,在第一步中開始的覆蓋層和值指示器動畫就會反轉。一個特殊的回呼函數 onChangeEnd() 也會發出結束值。

自訂觸控輸入選取

在上一節中,您看到了 Material 的預設拇指選擇行為的程式碼。但是,如果您想要不同的東西呢?以下程式碼顯示了如何撰寫一個始終選取最接近拇指的拇指選擇器,無論觸控軌道的哪個部分。

實作始終找到最接近拇指的自訂拇指選擇器:

獲得此自訂拇指後,您可以在全域應用程式主題中設定它:

或者,可以使用 SliderTheme 在特定滑桿實例上設定它:

控制允許的拇指位置

在上面,您看到了如何使用 SliderThemeData 自訂拇指的選擇方式。本節將說明如何限制拇指可以拖曳或設定到的位置。有兩種方法可以控制拇指的允許位置。可以透過來完成,也可以透過空間來完成。透過值可能很有用,例如,如果您有一個價格選擇器。假設允許的價格可以在 0 美元和 100 美元之間,但您希望範圍至少相隔 20 美元。因此,[$30, $50] 的範圍是允許的,但 [$33, $34] 的範圍是不允許的。只需按照以下方式調整 onChanged 函數:

如果只需要限制拇指的出現,則可以使用 minThumbSeparation 屬性來限制分隔 2 個拇指的邏輯像素數。預設的頂部拇指會在其周圍繪製一個白色外框,以更好地區分拇指之間的對比。以下是一張比較預設值 8 與自訂值 24 的圖:

繪製形狀

除了處理觸控輸入之外,RenderBox 還負責繪製 RangeSlider。它會按照以下順序繪製 RangeSlider 的元件:

  1. 軌道
  2. 覆蓋層
  3. 刻度線(如果為離散)
  4. 值指示器(如果可見)
  5. 拇指

這對於繪製自訂形狀非常重要。所有形狀實作都透過 5 個獨立的抽象類別從 RenderBox.paint() 方法中抽象出來,這使得 RangeSlider 的繪製或渲染完全可自訂和可主題化,因為這些類別存在於 SliderThemeData 物件上。

在下一節中,我們將說明如何使用自訂形狀覆蓋預設形狀。

使用自訂形狀

就像單個 Slider 一樣,所有構成滑桿的形狀都可以針對 RangeSlider 自訂。查看 此片段 了解如何自訂 Material Slider 的範例。

這是透過將自訂抽象形狀類別的實作傳遞到 SliderThemeData 來完成的。這利用了 RangeSliderThumbShape 類別來提供自訂拇指,這些拇指根據它們所在的哪一側具有不同的外觀。

自訂範圍拇指形狀可以按以下方式實作:

然後,可以在 SliderThemeData 上設定自訂範圍拇指形狀:

結語

Material 範圍滑桿是社群要求的元件。它可以開箱即用,也可以自訂以符合您的應用程式需求。可以在全域層級的主題中,或在逐個實例的基礎上,變更行為和視覺外觀。

本文中包含的所有程式碼的完整程式碼,以及更多範例,可以在 github 上的 Material 範例庫github 上的 Material 函式庫 中找到。

特別感謝 Shams Zakhour、Liam Spradlin、Barbara Eldredge、Cortney Cassidy 和 Will Larche。


Flutter 中的 Material 範圍滑桿 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。