Flutter 之 单选开关和复选框 (五十七)

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;
            });
          },
        ),
      ),
    );
  }
}

70.gif

颜色


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;
            });
          },
        ),
      ),
    );
  }
}

71.gif

图片


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;
            });
          },
        ),
      ),
    );
  }
}

72.gif

图片错误回调
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!;
            });
          },
        ),
      ),
    );
  }
}

73.gif

三态复选框
设置 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;
            });
          },
        ),
      ),
    );
  }
}

74.gif

颜色设置

使用 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;
}

75.gif

注意
通过Switch和Checkbox我们可以看到,虽然它们本身是与状态(是否选中)关联的,但它们却不是自己来维护状态,而是需要父组件来管理状态,然后当用户点击时,再通过事件通知给父组件,这样是合理的,因为Switch和Checkbox是否选中本就和用户数据关联,而这些用户数据也不可能是它们的私有状态。我们在自定义组件时也应该思考一下哪种状态的管理方式最为合理

参考:https://www.jianshu.com/p/ea8045998fd6
https://www.jianshu.com/p/e1bb77c67b8d

你可能感兴趣的:(Flutter 之 单选开关和复选框 (五十七))