Flutter 开关和切换高级指南
我們都熟悉家用開關來打開和關閉我們的照明系統和其他電器。 我們也熟悉切換按鈕; 如果您家里有電炊具或電磁爐,您可以在其電壓和烹飪功能之間切換。
同樣,我們的移動應用程序也有開關和撥動開關來打開/關閉 Wi-Fi、藍牙等。
今天,我們正在深入了解 Flutter 開關和切換的參數和屬性。
目錄
-
什么是開關小部件?
-
什么是切換小部件?
-
開關和撥動之間的關鍵區別
-
切換小部件示例
-
安卓
-
iOS
-
帶圖片的安卓開關
-
-
切換小部件示例
-
單個和必需的撥動開關
-
單個且不需要的撥動開關
-
需要多選
-
不需要的多項選擇
-
-
創建自定義動畫開關按鈕
-
用于開關和切換的流行 Flutter 包
什么是開關小部件?
開關按鈕是一個 Flutter 小部件,只有兩種狀態,真/假或開/關。 通常,開關是一個帶有拇指滑塊的按鈕,用戶可以將其從左拖動到右,反之亦然以在狀態之間切換。 它不會自行維護其狀態。 您必須致電 onChanged屬性以保持按鈕打開或關閉。
什么是切換小部件?
同樣,切換小部件只有兩種狀態:真/假或開/關。 但是切換小部件會創建多個按行排列的按鈕,允許用戶在它們之間切換。
開關和撥動之間的關鍵區別
這是移動應用程序中的用例問題。 在大多數情況下,這些小部件用于設置頁面。 如果您向下拖動移動應用程序的通知面板,您將看到一個切換按鈕網格。 但是當您進入設置頁面時,這些按鈕將更改為開關。
你一定明白其中的區別。 在您的移動應用程序中,如果您有一個只需要兩種狀態的控件列表,您應該使用開關。 如果一行或網格中有多個控件,則應使用切換。
切換小部件示例
Flutter 提供了三種類型的 switch 小部件:
超過 20 萬開發人員使用 LogRocket 來創造更好的數字體驗 了解更多 →
-
開關(安卓)
-
CupertinoSwitch (iOS)
-
Switch.adaptive(根據平臺適配)
讓我們看一下用于自定義小部件的最常用屬性:
Switch(安卓)
Switch(// thumb color (round icon)activeColor: Colors.amber,activeTrackColor: Colors.cyan,inactiveThumbColor: Colors.blueGrey.shade600,inactiveTrackColor: Colors.grey.shade400,splashRadius: 50.0,// boolean variable valuevalue: forAndroid,// changes the state of the switchonChanged: (value) => setState(() => forAndroid = value), ),CupertinoSwitch(iOS)
CupertinoSwitch(// overrides the default green color of the trackactiveColor: Colors.pink.shade200,// color of the round icon, which moves from right to leftthumbColor: Colors.green.shade900,// when the switch is offtrackColor: Colors.black12,// boolean variable valuevalue: forIos,// changes the state of the switchonChanged: (value) => setState(() => forIos = value), ),自適應開關小部件沒有任何獨特或不同的屬性。 但是安卓 Switch如果您想要圖像或圖標而不是通常的拇指顏色,可以進一步自定義小部件。 您需要使用資產圖像定義拇指圖像屬性。 請看下面的代碼。
安卓 Switch帶圖像
Switch(trackColor: MaterialStateProperty.all(Colors.black38),activeColor: Colors.green.withOpacity(0.4),inactiveThumbColor: Colors.red.withOpacity(0.4), // when the switch is on, this image will be displayedactiveThumbImage: const AssetImage('assets/happy_emoji.png'), // when the switch is off, this image will be displayedinactiveThumbImage: const AssetImage('assets/sad_emoji.png'),value: forImage,onChanged: (value) => setState(() => forImage = value), ),這就是代碼在運行中的樣子:
目前,我們不保存開關小部件的狀態; 我們只是在改變它。 接下來是創建一個小應用程序,我們將在其中將主題從淺色更改為深色,反之亦然,當您關閉應用程序時,它的狀態將被保存。
它是一個簡單的單頁應用程序,在 appBar,這將改變主題。
我已經使用 Flutter Hive 來保存應用程序的狀態。 您可以使用 SharedPreferences,但我選擇了 Hive,因為它是一個快速、輕量級的 NoSQL 數據庫,適用于 Flutter 和 Dart 應用程序。 如果您需要一個沒有大量關系的簡單鍵值數據庫,Hive 會很有幫助。 它使用起來毫不費力,并且是一個離線數據庫(在本地存儲數據)。
我們先來看代碼……
我們正在使用 ValueListenableBuilder更新用戶界面。 每次它偵聽的值發生變化時,它都會構建特定的小部件。 它的值與聽眾保持同步; 即,每當值發生變化時, ValueListenable監聽它并在不使用的情況下更新 UI setState()或任何其他狀態管理技術:
const themeBox = 'hiveThemeBox'; void main() async {await Hive.initFlutter();await Hive.openBox(themeBox);runApp(const MyApp()); } ? class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key); ?@overrideWidget build(BuildContext context) {//to update the UI without using setState()return ValueListenableBuilder(valueListenable: Hive.box(themeBox).listenable(),builder: (context, box, widget) {//saving the value inside the hive box,var darkMode = Hive.box(themeBox).get('darkMode', defaultValue: false);return MaterialApp(debugShowCheckedModeBanner: false,//switching between light and dark theme,themeMode: darkMode ? ThemeMode.dark : ThemeMode.light,title: 'Flutter Demo',darkTheme: ThemeData.dark(),home: HomePage(value: darkMode,));},);} } ? class HomePage extends StatelessWidget {final bool value;const HomePage({Key? key, required this.value}) : super(key: key); ?@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(value ? 'Hive Dark Mode' : 'Hive Light Mode'),actions: [Switch(value: value,onChanged: (val) {Hive.box(themeBox).put('darkMode', !value);},),],),body: Padding(padding: const EdgeInsets.all(8.0),child: Column(crossAxisAlignment: CrossAxisAlignment.stretch,children: [ ],),),);} }切換小部件示例
在這里,我們將看看在我們的應用程序中實現切換小部件的四種不同方法。
-
單一且必需:用戶必須從兩個選項中選擇至少一個
-
單一且不需要:用戶無需選擇任何選項
-
Multiple and required:用戶必須至少選擇一個給定選項,但也可以選擇多個選項
-
多選且非必選:用戶可以根據需要選擇或取消選擇,也可以選擇多個選項
首先,讓我們看一下切換小部件的標準屬性以對其進行自定義,然后我們將查看每個小部件的代碼及其插圖:
ToggleButtons(// list of booleansisSelected: isSelected,// text color of selected toggleselectedColor: Colors.white,// text color of not selected togglecolor: Colors.blue,// fill color of selected togglefillColor: Colors.lightBlue.shade900,// when pressed, splash color is seensplashColor: Colors.red,// long press to identify highlight colorhighlightColor: Colors.orange,// if consistency is needed for all text styletextStyle: const TextStyle(fontWeight: FontWeight.bold),// border properties for each togglerenderBorder: true,borderColor: Colors.black,borderWidth: 1.5,borderRadius: BorderRadius.circular(10),selectedBorderColor: Colors.pink, // add widgets for which the users need to togglechildren: [ ], // to select or deselect when pressedonPressed: (int newIndex) { } );單個和必需的撥動開關
首先,我們必須初始化一個布爾變量列表:
// one must always be true, means selected. List<bool> isSelected = [true, false, false];由于我們強制系統始終選擇至少一個選項,因此我們將一個值初始化為 true.
我們已經討論了自定義切換小部件的其他屬性。 現在我們將子小部件添加到它的 children財產。
注意,您必須添加與布爾值列表相同數量的子小部件。 否則會拋出錯誤。
// add widgets for which the users need to toggle children: const [Padding(padding: EdgeInsets.symmetric(horizontal: 12),child: Text('MALE', style: TextStyle(fontSize: 18)),),Padding(padding: EdgeInsets.symmetric(horizontal: 12),child: Text('FEMALE', style: TextStyle(fontSize: 18)),),Padding(padding: EdgeInsets.symmetric(horizontal: 12),child: Text('OTHER', style: TextStyle(fontSize: 18)),), ],接下來,我們必須將邏輯添加到 onPressed()內部切換小部件的屬性 setState()功能。
-
使用 for循環,我們將遍歷布爾值列表
-
使用
if聲明,我們將檢查
index值并始終將其設置為
true. 其他按鈕將設置為
false onPressed: (int newIndex) {setState(() {// looping through the list of booleans valuesfor (int index = 0; index < isSelected.length; index++) {// checking for the index valueif (index == newIndex) {// one button is always set to trueisSelected[index] = true;} else {// other two will be set to false and not selectedisSelected[index] = false;}}}); },
這就是我們最終產品的外觀。
來自 LogRocket 的更多精彩文章:
-
不要錯過 The Replay 來自 LogRocket 的精選時事通訊
-
了解 LogRocket 的 Galileo 如何消除噪音以主動解決應用程序中的問題
-
使用 React 的 useEffect 優化應用程序的性能
-
之間切換 在多個 Node 版本
-
了解如何 使用 AnimXYZ 為您的 React 應用程序制作動畫
-
探索 Tauri ,一個用于構建二進制文件的新框架
-
比較 NestJS 與 Express.js
單個且不需要的撥動開關
我們只需要進行兩項更改即可使其正常工作。 用戶只能從三個選項中選擇一個,但不是必須選擇它。
布爾變量列表中的值都初始化為 false:
// all values are false List<bool> isSelected = [false, false, false];在 - 的里面 if statement in the onPressed() function, we only toggle between buttons to set it to true:
onPressed: (int newIndex) {setState(() {// looping through the list of booleans valuesfor (int index = 0; index < isSelected.length; index++) {if (index == newIndex) {// toggling between the button to set it to trueisSelected[index] = !isSelected[index];} else {// other two buttons will not be selected and are set to falseisSelected[index] = false;}}}); },需要多選
如前所述,用戶可以選擇多個選項,但系統將始終保持至少一個選項處于選中狀態。
是的,您猜對了,布爾值列表中的一個值將是 true:
List<bool> isSelected = [true, false, false];里面的事情變得有點有趣 onPressed功能。
首先,我們添加一個變量來循環布爾值列表,并確保值為真; 因此,始終至少選擇一個按鈕:
final isOneSelected = isSelected.where((element) => element).length == 1;如果只選擇了一個按鈕,則用戶無法將其切換到 false直到選擇另一個選項:
if (isOneSelected && isSelected[newIndex]) return;接下來,內 setState()函數,我們再次遍歷我們的列表,檢查新的索引值,并在新舊索引之間切換:
setState(() {// looping through the list of booleansfor (int index = 0; index < isSelected.length; index++) {// checking for the index valueif (index == newIndex) {// toggle between the old index and new index valueisSelected[index] = !isSelected[index];}} });不需要的多項選擇
這很簡單。 我制作了一行文本編輯選項,您通常在任何文本編輯器中都會看到這些選項來格式化書面文本。 有四個選項,所以我們的列表中有四個值,并且都設置為 false:
List<bool> isSelected = [false, false, false, false];在我們的 onPressed()功能,我們只需在 true和 false價值觀:
onPressed: (int index) {setState(() {// simply toggling buttons between true and false stateisSelected[index] = !isSelected[index];});我們已經完成了對開關和切換小部件以及如何以通常方式使用它的解釋。 現在,讓我們通過創建一個自定義動畫開關按鈕來進行一些復雜的編程,在實現下一個代碼集后,該按鈕將如下圖所示。
創建自定義動畫開關按鈕
我們將此按鈕分為兩部分。 第一個是我命名為的無狀態小部件 CustomAnimatedSwitch. 在這個無狀態小部件中,我們將創建自定義開關。 稍后,我們會將它添加到有狀態小部件中以使用 setState()功能來打開和關閉。
簡壁紙App,全是4K壁紙超給力,極品內容已全部解鎖!
第一步:添加依賴
simple_animations: ^5.0.0+2第 2 步:定義變量
首先,我們將使用枚舉和布爾值定義命名常量變量:
enum _CustomSwitchParams { paddingLeft, color, text, rotation }final bool toggle;其次,由于我們使用的是帶有級聯符號(雙點運算符)的簡單動畫包,因此我們在 MovieTween我們為訪問其屬性而創建的對象。 基本上,我們正在向我們之前添加的枚舉添加動畫:
var customTween = MovieTween()..scene(duration: const Duration(seconds: 1)).tween(_CustomSwitchParams.paddingLeft, 0.0.tweenTo(60.0))..scene(duration: const Duration(seconds: 1)).tween(_CustomSwitchParams.color, Colors.red.tweenTo(Colors.green))..scene(duration: const Duration(milliseconds: 500)).tween(_CustomSwitchParams.text, ConstantTween('OFF')).thenTween(_CustomSwitchParams.text, ConstantTween('ON'),duration: const Duration(milliseconds: 500))..scene(duration: const Duration(seconds: 1)).tween(_CustomSwitchParams.rotation, (-2 * pi).tweenTo(0.0));第 3 步: CustomAnimationBuilder
接下來,我們將構建我們的 CustomAnimationBuilder小部件并定義其所需的屬性來組裝開關動畫:
CustomAnimationBuilder<Movie>(// control of the animationcontrol: toggle ? Control.play : Control.playReverse,// the relative position where animation will startstartPosition: toggle ? 1.0 : 0.0,// define unique keykey: const Key('0'),duration: customTween.duration * 1.2,// movie tween objecttween: customTween,curve: Curves.easeInOut,builder: (context, value, child) {return Container(decoration:_outerDecoration(color: value.get(_CustomSwitchParams.color)),width: 100.0,height: 40.0,padding: const EdgeInsets.all(4.0),child: Stack(children: [Positioned(child: Padding(padding: EdgeInsets.only(left: value.get(_CustomSwitchParams.paddingLeft),),child: Transform.rotate(angle: value.get(_CustomSwitchParams.rotation),child: Container(decoration: _innerDecoration(color: value.get(_CustomSwitchParams.color),),width: 30.0,child: Center(child: Text(value.get(_CustomSwitchParams.text),style: const TextStyle(height: 1.5,fontSize: 12,fontWeight: FontWeight.bold,color: Colors.white),),),),),),),],),);},); }第4步: CustomSwitchButton(有狀態小部件)
來到創建自定義開關按鈕的第二部分,我們必須添加另一個包含有狀態小部件的 Dart 文件,我們將其稱為 CustomSwitchButton.
首先,定義一個布爾變量并將其值設置為 false:
bool _switched = false;其次,創建一個方法 setState()切換功能 true和 false:
void toggleSwitch() {setState(() {_switched = !_switched;}); }最后,我們添加我們的 CustomAnimatedSwitch到這個包裹著的 Dart 文件 GestureDetector,添加 toggleSwitch的方法 onTap()功能。
而已! 我們擁有功能齊全的定制動畫開關按鈕。 請查看下面的代碼和圖像:
@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Custom Animated Switch'),),body: GestureDetector(onTap: toggleSwitch,child: Center(child: Column(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [const Padding(padding: EdgeInsets.all(10.0),child: Text('Tap to Check Custom Animated Switch'),),const SizedBox(height: 20.0,),CustomAnimatedSwitch(toggle: _switched),],),),),);} }用于開關和切換的流行 Flutter 包
如果您不想創建自己的開關按鈕,您可以隨時使用以下任何包,它們的功能與我們制作自己的自定義動畫開關完全相同。
AnimatedToggleSwitch:用于多種選擇的簡單和動畫切換開關。 如果您不想使用下拉菜單之類的東西,這是一個不錯的選擇 ?
FlutterSwitch:為 Flutter 創建的易于實現的自定義開關。 給它一個自定義的高度和寬度,開關和切換的邊框,邊框半徑,顏色,切換大小,顯示 開 和 關 文本的選擇,并能夠在切換內添加一個圖標
ToggleSwitch:一個簡單的切換開關小部件。 它可以完全自定義所需的圖標、寬度、顏色、文本、圓角半徑、動畫等。它還保持選擇狀態
我留下了 整個項目的鏈接 ,你可以在我的 GitHub 頁面上找到它。 如果有任何問題或者您可以改進代碼,請告訴我,我會讓您訪問我的項目。
非常感謝并保持安全!
LogRocket :全面了解您的網絡和移動應用程序
LogRocket 是一個前端應用程序監控解決方案,可讓您重現問題,就好像它們發生在您自己的瀏覽器中一樣。 無需猜測錯誤發生的原因,或要求用戶提供屏幕截圖和日志轉儲,LogRocket 可讓您重播會話以快速了解問題所在。 無論框架如何,它都可以完美地與任何應用程序配合使用,并且具有用于記錄來自 Redux、Vuex 和 @ngrx/store 的附加上下文的插件。
除了記錄 Redux 操作和狀態之外,LogRocket 還記錄控制臺日志、JavaScript 錯誤、堆棧跟蹤、帶有標頭 + 正文的網絡請求/響應、瀏覽器元數據和自定義日志。 它還檢測 DOM 以記錄頁面上的 HTML 和 CSS,即使是最復雜的單頁和移動應用程序也能重新創建像素完美的視頻。
總結
以上是生活随笔為你收集整理的Flutter 开关和切换高级指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 入门级测试Kotlin实现PopWind
- 下一篇: PS:金色哥特艺术文字