Material 组件库中提供了 Material 风格的单选开关Switch和复选框Checkbox,虽然它们都是继承自StatefulWidget,但它们本身不会保存当前选中状态,选中状态都是由父组件来管理的。当Switch或Checkbox被点击时,会触发它们的onChanged回调,我们可以在此回调中处理选中状态改变逻辑。
1. Switch
Switch 定义
const Switch({
Key? key,
required this.value,
required this.onChanged,
this.activeColor,
this.activeTrackColor,
this.inactiveThumbColor,
this.inactiveTrackColor,
this.activeThumbImage,
this.onActiveThumbImageError,
this.inactiveThumbImage,
this.onInactiveThumbImageError,
this.thumbColor,
this.trackColor,
this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.start,
this.mouseCursor,
this.focusColor,
this.hoverColor,
this.overlayColor,
this.splashRadius,
this.focusNode,
this.autofocus = false,
})
1.1 Switch 属性介绍
Switch属性 | 介绍 |
---|---|
value | @required bool,value = true 时为打开状态,false 关闭 |
onChanged | 点击事件 |
activeColor | 打开状态下滑块颜色 |
activeTrackColor | 打开状态下轨道颜色 |
inactiveThumbColor | 关闭状态下滑块颜色 |
inactiveTrackColor | 关闭状态下轨道颜色 |
activeThumbImage | 打开状态下滑块图片 |
onActiveThumbImageError | 打开状态下滑块图片加载失败回调 |
inactiveThumbImage | 关闭状态下滑块图片 |
onInactiveThumbImageError | 关闭状态下滑块图片加载失败回调 |
materialTapTargetSize | 内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小 |
dragStartBehavior | 启动阻力,默认为 DragStartBehavior.start |
mouseCursor | 鼠标光标 |
focusColor | 聚焦颜色 |
hoverColor | 悬停颜色 |
focusNode | 焦点控制 |
autofocus | 自动聚焦,默认为 false |
1.2 示例
基本使用
class MSSwitchDemo1 extends StatefulWidget {
const MSSwitchDemo1({Key? key}) : super(key: key);
@override
State createState() => _MSSwitchDemo1State();
}
class _MSSwitchDemo1State extends State {
var _switchValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Switch(
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
},
),
),
);
}
}
颜色
class MSSwitchDemo2 extends StatefulWidget {
const MSSwitchDemo2({Key? key}) : super(key: key);
@override
State createState() => _MSSwitchDemo2State();
}
class _MSSwitchDemo2State extends State {
var _switchValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Switch(
activeColor: Colors.red,
activeTrackColor: Colors.red[100],
inactiveThumbColor: Colors.green,
inactiveTrackColor: Colors.green[100],
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
},
),
),
);
}
}
图片
class MSSwitchDemo3 extends StatefulWidget {
const MSSwitchDemo3({Key? key}) : super(key: key);
@override
State createState() => _MSSwitchDemo3State();
}
class _MSSwitchDemo3State extends State {
var _switchValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Switch(
activeTrackColor: Colors.red[100],
inactiveTrackColor: Colors.green[100],
activeThumbImage: AssetImage("assets/images/tx1.jpeg"),
inactiveThumbImage: AssetImage("assets/images/tx2.jpeg"),
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
},
),
),
);
}
}
图片错误回调
onActiveThumbImageError 与 onInactiveThumbImageError 分别是选中和未选中状态下,滑块图片错误回调。一般来说本地图片不会有什么问题,当加载网络图片时,有时候就会出现这个问题。
我们来给 activeThumbImage 与 inactiveThumbImage 两个错误的网络地址,当拿不到正确的图片时,就会走错误回调了。
class MSSwitchDemo4 extends StatefulWidget {
const MSSwitchDemo4({Key? key}) : super(key: key);
@override
State createState() => _MSSwitchDemo4State();
}
class _MSSwitchDemo4State extends State {
var _switchValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Switch(
activeTrackColor: Colors.red[100],
inactiveTrackColor: Colors.green[100],
activeThumbImage: NetworkImage("http://images/tx1.jpeg"),
inactiveThumbImage: NetworkImage("http://images/tx3.jpeg"),
onActiveThumbImageError: (err, stack) {
print("onActiveThumbImageError $err");
},
onInactiveThumbImageError: (err, stack) {
print("onInactiveThumbImageError $err");
},
value: _switchValue,
onChanged: (value) {
setState(() {
_switchValue = value;
});
},
),
),
);
}
}
flutter: onInactiveThumbImageError SocketException: Failed host lookup: 'images' (OS Error: nodename nor servname provided, or not known, errno = 8)
flutter: onActiveThumbImageError SocketException: Failed host lookup: 'images' (OS Error: nodename nor servname provided, or not known, errno = 8)
2. Checkbox
Checkbox 定义
const Checkbox({
Key? key,
required this.value,
this.tristate = false,
required this.onChanged,
this.mouseCursor,
this.activeColor,
this.fillColor,
this.checkColor,
this.focusColor,
this.hoverColor,
this.overlayColor,
this.splashRadius,
this.materialTapTargetSize,
this.visualDensity,
this.focusNode,
this.autofocus = false,
this.shape,
this.side,
})
2.1 CheckBox 属性介绍
CheckBox属性 | 介绍 |
---|---|
value | @required 是否选中 |
tristate | 三态复选框,默认 false,当设置为 true 时,设置 value = null,复选框中间会变成破折号(-) |
onChanged | @required 点击事件 |
mouseCursor | 鼠标光标 |
activeColor | 选中时填充颜色 |
checkColor | 选中时中间✔️颜色 |
focusColor | 聚焦颜色 |
hoverColor | 悬停颜色 |
materialTapTargetSize | 内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小 |
visualDensity | 布局紧凑设置 |
focusNode | 焦点控制 |
autofocus | 自动聚焦,默认为 false |
2.2 示例
基本使用
class MSCheckBoxDemo1 extends StatefulWidget {
const MSCheckBoxDemo1({Key? key}) : super(key: key);
@override
State createState() => _MSCheckBoxDemo1State();
}
class _MSCheckBoxDemo1State extends State {
var _checkBoxValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Checkbox(
value: _checkBoxValue,
onChanged: (value) {
setState(() {
_checkBoxValue = value!;
});
},
),
),
);
}
}
三态复选框
设置 tristate == true 时,value可以为null,为null时显示破折号—
class MSCheckBoxDemo2 extends StatefulWidget {
const MSCheckBoxDemo2({Key? key}) : super(key: key);
@override
State createState() => _MSCheckBoxDemo2State();
}
class _MSCheckBoxDemo2State extends State {
bool? _checkBoxValue = null;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Checkbox(
value: _checkBoxValue,
tristate: true,
onChanged: (value) {
setState(() {
_checkBoxValue = value;
});
},
),
),
);
}
}
颜色设置
使用 activeColor 改变选中时填充颜色。
使用 checkColor 改变选中时中间✔️颜色
class MSCheckBoxDemo3 extends StatefulWidget {
const MSCheckBoxDemo3({Key? key}) : super(key: key);
@override
State createState() => _MSCheckBoxDemo3State();
}
class _MSCheckBoxDemo3State extends State {
bool? _checkBoxValue = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Checkbox(
activeColor: Colors.red,
checkColor: Colors.green[800],
value: _checkBoxValue,
onChanged: (value) {
setState(() {
_checkBoxValue = value;
});
},
),
),
);
}
}
CheckBox 进阶
这里做一个例子,像菜单一样的多选功能。
根据需要,批量创建复选框及标题。
创建数据模型,保存每一个标题名称及状态。
保存当前选中状态,以及数据处理
class MSCheckBoxDemo4 extends StatefulWidget {
const MSCheckBoxDemo4({Key? key}) : super(key: key);
@override
State createState() => _MSCheckBoxDemo4State();
}
class _MSCheckBoxDemo4State extends State {
List _datas = [];
@override
void initState() {
_datas.add(MSCheckBoxMode(false, "游戏"));
_datas.add(MSCheckBoxMode(false, "娱乐"));
_datas.add(MSCheckBoxMode(false, "购物"));
_datas.add(MSCheckBoxMode(false, "社交"));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CheckBoxDemo"),
),
body: SingleChildScrollView(
child: Column(
children: _datas.map((e) {
return _buildCheckBoxRow(e);
}).toList(),
),
),
bottomSheet: _buildBottomSheet(),
);
}
Widget _buildCheckBoxRow(MSCheckBoxMode mode) {
return Row(
children: [
Checkbox(
value: mode.selected,
onChanged: (value) {
mode.selected = !mode.selected;
setState(() {});
},
),
Text(mode.text),
],
);
}
Widget _buildBottomSheet() {
return BottomSheet(
enableDrag: false,
onClosing: () {},
builder: (ctx) {
return Container(
width: double.infinity,
height: 60,
color: Colors.cyan,
child: Text(_getSelectedBoxs()),
alignment: Alignment.center,
);
},
);
}
String _getSelectedBoxs() {
String str = "";
_datas.forEach((element) {
if (element.selected) {
str += "${element.text} ";
}
});
return str;
}
}
class MSCheckBoxMode {
MSCheckBoxMode(this.selected, this.text);
bool selected;
String text;
}
注意
通过Switch和Checkbox我们可以看到,虽然它们本身是与状态(是否选中)关联的,但它们却不是自己来维护状态,而是需要父组件来管理状态,然后当用户点击时,再通过事件通知给父组件,这样是合理的,因为Switch和Checkbox是否选中本就和用户数据关联,而这些用户数据也不可能是它们的私有状态。我们在自定义组件时也应该思考一下哪种状态的管理方式最为合理
参考:https://www.jianshu.com/p/ea8045998fd6
https://www.jianshu.com/p/e1bb77c67b8d