【文章內容使用 Gemini 1.5 Pro 自動產生】
Flutter 中的 Material RangeSlider
範圍滑桿是 Flutter 1.7 中釋出的高度自訂元件,用於選擇一組值。本文說明了範圍滑桿是什麼,為什麼您可能需要使用它,以及如何使用 Material 主題自訂 Flutter RangeSlider 的行為和外觀。
為什麼要使用範圍滑桿?
滑桿元件可以提供單一選取或多重選取,在離散或連續軌道上。與單一選取滑桿不同的是,單一選取滑桿預先確定最小值或最大值,並且可以在一個方向上調整選取,範圍滑桿具有兩個選取點,允許靈活調整最小值和最大值點。這種靈活性使其成為有用的元件,適用於使用者希望控制特定範圍的情況,例如指示價格點或時間長度。
結構和實作
RangeSlider 由 5 個部分組成:
- 一個軌道,拇指可以在上面滑動。
- 當 RangeSlider 為離散時,軌道上的刻度線。
- 2 個拇指(或旋鈕),表示範圍的最小值和最大值。
- 值指示器,在定義標籤且 showValueIndicator 與滑桿類型相符時,顯示拇指值的標籤。
- 當拇指被按下時,顯示在拇指上的覆蓋層。
我們需要 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 的元件:
- 軌道
- 覆蓋層
- 刻度線(如果為離散)
- 值指示器(如果可見)
- 拇指
這對於繪製自訂形狀非常重要。所有形狀實作都透過 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,人們在那裡透過突出顯示和回應這個故事來繼續討論。