Switch
就是切換開關,透過 value
特性設定 true
或 false
,來改變 Switch
建構時的初始外觀,true
會繪製為「開」的外觀,false
是繪製為「關」的外觀。
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Openhome.cc')),
body: Row(
children: [
Switch(value: true, onChanged: (value) => print(value)),
Switch(value: false, onChanged: (value) => print(value))
],
),
)
)
);
顯示結果如下:
當你操作 Switch
時,會觸發 onChanged
,注意,不一定要切換過去,只要有動到,就算只是點一下,也會觸發 onChanged
,處理器的 value
會是 Switch
建構時指定的 value
之相反值,例如,點選上例第一個 Switch
,始終都會傳入 false
,就算你怎麼切換,一定都是 false
…
這是怎麼一回事呢?官方文件上說到,Switch
本身不維護任何狀態,這說法有點模糊,Switch
繼承了 StatefulWidget
,內部是有維護外觀的狀態,因此你才可以在 Switch
上切換外觀,官方文件上說到不維護的狀態,應該是指 value
的狀態,不會隨著你操作後的外觀而變動,value
始終都會是 Switch
建構時指定的值。
乍看這元件設計上有點怪異,外觀與 value
並不同步?onChanged
是有動到元件就會觸發?傳入的 value
始終都會是 Switch
建構時指定的值?
onChanged
的設計,應該是為了使用者的可用性,只要點選,程式設計上就可以改變外觀,不一定要拉到另一端;至於不維護外觀與 value
的同步,應該是為了分開 UI 狀態及應用程式狀態的概念,這是近來前端狀態管理時,許多開發者在倡導的設計方式。
總之,既然它是這麼設計了,那麼該怎麼上例該怎麼做,才會讓 Switch
外觀狀態切換後,應用程式有對應的開、關狀態呢?
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Openhome.cc')),
body: PowerSavingSwitch(),
)
)
);
class PowerSavingSwitch extends StatefulWidget {
@override
State<StatefulWidget> createState() => _PowerSavingState();
}
class _PowerSavingState extends State<PowerSavingSwitch> {
bool saving = false;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('省電模式'),
Switch(
value: saving, // 依 saving 決定 Switch 外觀狀態
onChanged: (value) {
setState(() {
saving = !saving; // 改變 saving
});
})
],
);
}
}
這麼一來,只要點選,就會自動切換,不用自行拉到另一頭了:
至於 Checkbox
應該不用太多著墨了,就是核取方塊的外觀,可以是雙態或三態,這是透過 tristate
特性來控制;類似地,也是外觀狀態與應用程式狀態應該分離的設計概念,因此使用上要注意的,與 Switch
相同,或者應該說,Flutter 鼓勵外觀狀態與應用程式狀態應該分離,有不少元件都是這麼設計。
直接來看個 Checkbox
的範例(只是把上例的 Switch 字眼都換為 Checkbox 罷了)
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Openhome.cc')),
body: PowerSavingCheckbox(),
)
)
);
class PowerSavingCheckbox extends StatefulWidget {
@override
State<StatefulWidget> createState() => _PowerSavingState();
}
class _PowerSavingState extends State<PowerSavingCheckbox> {
bool saving = false;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('省電模式'),
Checkbox(
value: saving,
onChanged: (value) {
setState(() {
saving = !saving;
});
})
],
);
}
}
執行結果如下: