chenBingX
12/30/2019 - 3:44 AM

fradio组件示例

fradio组件示例

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  var groupValue = '1';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              const SizedBox(height: 35),
              Text('自定义 Radio'),
              const SizedBox(height: 10),
              FRadio(
                value: '1',
                onChanged: (value) {},
                groupValue: '0',
                asCheckbox: true,
                width: 80,
                height: 30,
                unselectedChild: Container(
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                      border: Border.all(width: 2, color: Colors.grey[300]),
                      borderRadius: BorderRadius.all(Radius.circular(5))),
                  child: Text(
                    '未选中',
                    style: TextStyle(color: Colors.redAccent),
                  ),
                ),
                selectedChild: Container(
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                      border: Border.all(width: 2, color: Colors.grey[300]),
                      borderRadius: BorderRadius.all(Radius.circular(6))),
                  child: Text(
                    '选中',
                    style: TextStyle(color: Colors.greenAccent),
                  ),
                ),
              ),
              const SizedBox(height: 35),
              Text('Radio.style1'),
              const SizedBox(height: 10),
              Container(
                padding: EdgeInsets.fromLTRB(12, 0, 12, 0),
                margin: EdgeInsets.fromLTRB(12, 0, 12, 0),
                decoration: BoxDecoration(
                    color: Color(0xffffAc500),
                    borderRadius: BorderRadius.all(Radius.circular(6))),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text(
                      '快点击右侧 ✅ 试试啊!',
                      style: TextStyle(color: Colors.black),
                    ),
                    FRadio.style1(
                      value: '2',
                      groupValue: '2',
                      onChanged: (value) {},
                      asCheckbox: true,
                      color: Colors.white,
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 35),
              Text('Radio.style2'),
              const SizedBox(height: 10),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      Text(
                        '未选中状态',
                        style: TextStyle(color: Colors.grey, fontSize: 10),
                      ),
                      const SizedBox(height: 6),
                      FRadio.style2(
                        value: '2',
                        groupValue: '0',
                        onChanged: (value) {},
                        asCheckbox: true,
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Text(
                        '选中状态',
                        style: TextStyle(color: Colors.grey, fontSize: 10),
                      ),
                      const SizedBox(height: 6),
                      FRadio.style2(
                        value: '2',
                        groupValue: '2',
                        onChanged: (value) {},
                        asCheckbox: true,
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Text(
                        '不可用状态-选中',
                        style: TextStyle(color: Colors.grey, fontSize: 10),
                      ),
                      const SizedBox(height: 6),
                      FRadio.style2(
                        value: '2',
                        groupValue: '2',
                        onChanged: (value) {},
                        asCheckbox: true,
                        enable: false,
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Text(
                        '不可用状态-未选中',
                        style: TextStyle(color: Colors.grey, fontSize: 10),
                      ),
                      const SizedBox(height: 6),
                      FRadio.style2(
                        value: '2',
                        groupValue: '1',
                        onChanged: (value) {},
                        asCheckbox: true,
                        enable: false,
                      ),
                    ],
                  ),
                ],
              ),
              const SizedBox(height: 35),
              Text('Radio.style3'),
              const SizedBox(height: 10),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      Column(
                        children: <Widget>[
                          Text(
                            '未选中状态',
                            style: TextStyle(color: Colors.grey, fontSize: 10),
                          ),
                          const SizedBox(height: 6),
                          FRadio.style3(
                            value: '2',
                            groupValue: '0',
                            onChanged: (value) {},
                            asCheckbox: true,
                          ),
                        ],
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Column(
                        children: <Widget>[
                          Text(
                            '选中状态',
                            style: TextStyle(color: Colors.grey, fontSize: 10),
                          ),
                          const SizedBox(height: 6),
                          FRadio.style3(
                            value: '2',
                            groupValue: '2',
                            onChanged: (value) {},
                            asCheckbox: true,
                          ),
                        ],
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Column(
                        children: <Widget>[
                          Text(
                            '不可用状态-选中',
                            style: TextStyle(color: Colors.grey, fontSize: 10),
                          ),
                          const SizedBox(height: 6),
                          FRadio.style3(
                            value: '2',
                            groupValue: '2',
                            onChanged: (value) {},
                            asCheckbox: true,
                            enable: false,
                          ),
                        ],
                      ),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Column(
                        children: <Widget>[
                          Text(
                            '不可用状态-未选中',
                            style: TextStyle(color: Colors.grey, fontSize: 10),
                          ),
                          const SizedBox(height: 6),
                          FRadio.style3(
                            value: '2',
                            groupValue: '0',
                            onChanged: (value) {},
                            asCheckbox: true,
                            enable: false,
                          ),
                        ],
                      ),
                    ],
                  ),
                ],
              ),
              const SizedBox(height: 35),
              Text('如何实现单选?'),
              Text(
                '通过一个公共变量 groupValue,可轻松实现单选!',
                style: TextStyle(fontSize: 10),
              ),
              const SizedBox(height: 10),
              Container(
                padding: EdgeInsets.fromLTRB(12, 0, 12, 0),
                child: Column(
                  children: <Widget>[
                    Divider(
                      height: 0.5,
                      color: Colors.grey[300],
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '标题0',
                          style: TextStyle(color: Colors.black),
                        ),
                        FRadio.style1(
                          value: '0',
                          groupValue: groupValue,
                          onChanged: (value) {
                            setState(() {
                              groupValue = value;
                            });
                          },
                          asCheckbox: true,
                        ),
                      ],
                    ),
                    Divider(
                      height: 0.5,
                      color: Colors.grey[300],
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '标题1',
                          style: TextStyle(color: Colors.black),
                        ),
                        FRadio.style1(
                          value: '1',
                          groupValue: groupValue,
                          onChanged: (value) {
                            setState(() {
                              groupValue = value;
                            });
                          },
                          asCheckbox: true,
                        ),
                      ],
                    ),
                    Divider(
                      height: 0.5,
                      color: Colors.grey[300],
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '标题2',
                          style: TextStyle(color: Colors.black),
                        ),
                        FRadio.style1(
                          value: '2',
                          groupValue: groupValue,
                          onChanged: (value) {
                            setState(() {
                              groupValue = value;
                            });
                          },
                          asCheckbox: true,
                        ),
                      ],
                    ),
                    Divider(
                      height: 0.5,
                      color: Colors.grey[300],
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

class FRadio<T> extends StatefulWidget {
  final T value;

  T groupValue;

  final ValueChanged<T> onChanged;

  bool asCheckbox = false;

  Widget unselectedChild;

  Widget selectedChild;

  Widget disableChild;

  bool enable = true;

  double width;

  double height;

  T cacheGroupValue;

  FRadio({
    Key key,
    @required this.value,
    @required this.groupValue,
    @required this.onChanged,
    this.width = 42,
    this.height = 42,
    this.enable = true,
    this.asCheckbox = false,
    this.unselectedChild,
    this.selectedChild,
    this.disableChild,
  })  : cacheGroupValue = groupValue,
        assert(unselectedChild != null && selectedChild != null),
        assert(!(!enable && disableChild == null),
        "The 'disableChild' param can't be null when 'enable=false'."),
        super(key: key);

  FRadio.style1({
    Key key,
    @required this.value,
    @required this.groupValue,
    @required this.onChanged,
    this.width = 42,
    this.height = 42,
    this.enable = true,
    this.asCheckbox = false,
    Color color,
  })  : this.unselectedChild = Container(
    color: Colors.transparent,
    width: width,
    height: height,
  ),
        this.selectedChild = Container(
          width: width,
          height: height,
          child: Icon(
            Icons.check,
            color: color ?? Color(0xffFCA500),
            size: width.toDouble() / 42.toDouble() * 30.toDouble(),
          ),
        ),
        this.disableChild = Container(
          color: Colors.transparent,
          width: width,
          height: height,
        ),
        super(key: key);

  FRadio.style2({
    Key key,
    @required this.value,
    @required this.groupValue,
    @required this.onChanged,
    this.width = 42,
    this.height = 42,
    this.enable = true,
    this.asCheckbox = false,
    Color color,
  })  : this.unselectedChild = Container(
    decoration: BoxDecoration(
      // 设置边框
        border: Border.all(
            width: width / 42 * 2, color: color ?? Color(0xffE0E0E0)),
        // 设置圆角
        borderRadius: BorderRadius.all(Radius.circular(width / 42 * 6))),
  ),
        this.selectedChild = Container(
            decoration: BoxDecoration(
                color: Colors.white,
                // 设置边框
                border: Border.all(
                    width: width / 42 * 2, color: color ?? Color(0xffFCA500)),
                // 设置圆角
                borderRadius:
                BorderRadius.all(Radius.circular(width / 42 * 6))),
            child: Icon(
              Icons.check,
              color: color ?? Color(0xffFCA500),
              size: width.toDouble() / 42.toDouble() * 30.toDouble(),
            )),
        this.disableChild = Container(
          decoration: BoxDecoration(
              color: Color(0xffE0E0E0),
              // 设置边框
              border:
              Border.all(width: width / 42 * 2, color: Color(0xffCCCCCC)),
              // 设置圆角
              borderRadius: BorderRadius.all(Radius.circular(width / 42 * 6))),
          child: value == groupValue
              ? Icon(
            Icons.check,
            color: Color(0xffCCCCCC),
            size: width.toDouble() / 42.toDouble() * 30.toDouble(),
          )
              : null,
        ),
        super(key: key);

  FRadio.style3({
    Key key,
    @required this.value,
    @required this.groupValue,
    @required this.onChanged,
    this.width = 42,
    this.height = 42,
    this.enable = true,
    this.asCheckbox = false,
    Color color1,
    Color color2,
  })  : this.unselectedChild = Container(
    decoration: BoxDecoration(
      // 设置边框
        border: Border.all(
            width: width / 42 * 2, color: color1 ?? Color(0xffFF9F02)),
        // 设置圆角
        borderRadius: BorderRadius.all(Radius.circular(width / 2))),
  ),
        this.selectedChild = Container(
            decoration: BoxDecoration(
                gradient: LinearGradient(
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                    colors: [
                      color1 ?? Color(0xffFCD71E),
                      color2 ?? Color(0xffFF9F02)
                    ]),
                // 设置圆角
                borderRadius: BorderRadius.all(Radius.circular(width / 2))),
            child: Icon(
              Icons.check,
              color: Color(0xffffffff),
              size: width.toDouble() / 42.toDouble() * 30.toDouble(),
            )),
        this.disableChild = Container(
          decoration: BoxDecoration(
              color: Color(0xffE0E0E0),
              // 设置边框
              border:
              Border.all(width: width / 42 * 2, color: Color(0xffCCCCCC)),
              // 设置圆角
              borderRadius: BorderRadius.all(Radius.circular(width / 2))),
          child: value == groupValue
              ? Icon(
            Icons.check,
            color: Color(0xffCCCCCC),
            size: width.toDouble() / 42.toDouble() * 30.toDouble(),
          )
              : null,
        ),
        super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _Radio<T>();
  }
}

class _Radio<T> extends State<FRadio<T>> {
  bool get _enabled => widget.enable && widget.onChanged != null;

  bool get _selected => widget.value == widget.groupValue;

  _handOnTap() {
    if (widget.asCheckbox) {
      setState(() {
        if (widget.groupValue == widget.value) {
          widget.groupValue = widget.cacheGroupValue;
        } else {
          widget.groupValue = widget.value;
        }
      });
    }
    widget.onChanged(widget.value);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _enabled ? _handOnTap : null,
      child: Container(
//        color: Colors.grey,
        width: widget.width,
        height: widget.height,
        child: _buildChild(),
      ),
    );
  }

  _buildChild() {
    if (widget.enable) {
      return _selected ? widget.selectedChild : widget.unselectedChild;
    } else {
      return widget.disableChild;
    }
  }
}