dart Flutter:自定义单选按钮

nkoocmlb  于 2023-05-11  发布在  Flutter
关注(0)|答案(8)|浏览(176)

如何在flutter

中创建这样的自定义单选按钮组

ukxgm1gy

ukxgm1gy1#

下面是完整的代码

class CustomRadio extends StatefulWidget {
  @override
  createState() {
    return new CustomRadioState();
  }
}

class CustomRadioState extends State<CustomRadio> {
  List<RadioModel> sampleData = new List<RadioModel>();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    sampleData.add(new RadioModel(false, 'A', 'April 18'));
    sampleData.add(new RadioModel(false, 'B', 'April 17'));
    sampleData.add(new RadioModel(false, 'C', 'April 16'));
    sampleData.add(new RadioModel(false, 'D', 'April 15'));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("ListItem"),
      ),
      body: new ListView.builder(
        itemCount: sampleData.length,
        itemBuilder: (BuildContext context, int index) {
          return new InkWell(
            //highlightColor: Colors.red,
            splashColor: Colors.blueAccent,
            onTap: () {
              setState(() {
                sampleData.forEach((element) => element.isSelected = false);
                sampleData[index].isSelected = true;
              });
            },
            child: new RadioItem(sampleData[index]),
          );
        },
      ),
    );
  }
}

class RadioItem extends StatelessWidget {
  final RadioModel _item;
  RadioItem(this._item);
  @override
  Widget build(BuildContext context) {
    return new Container(
      margin: new EdgeInsets.all(15.0),
      child: new Row(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          new Container(
            height: 50.0,
            width: 50.0,
            child: new Center(
              child: new Text(_item.buttonText,
                  style: new TextStyle(
                      color:
                          _item.isSelected ? Colors.white : Colors.black,
                      //fontWeight: FontWeight.bold,
                      fontSize: 18.0)),
            ),
            decoration: new BoxDecoration(
              color: _item.isSelected
                  ? Colors.blueAccent
                  : Colors.transparent,
              border: new Border.all(
                  width: 1.0,
                  color: _item.isSelected
                      ? Colors.blueAccent
                      : Colors.grey),
              borderRadius: const BorderRadius.all(const Radius.circular(2.0)),
            ),
          ),
          new Container(
            margin: new EdgeInsets.only(left: 10.0),
            child: new Text(_item.text),
          )
        ],
      ),
    );
  }
}

class RadioModel {
  bool isSelected;
  final String buttonText;
  final String text;

  RadioModel(this.isSelected, this.buttonText, this.text);
}

用途:

void main() {
  runApp(new MaterialApp(
    home: new CustomRadio(),
  ));
}

截图:

nlejzf6q

nlejzf6q2#

截图(Null safe)

完整代码:

1.创建此自定义类。

class MyRadioListTile<T> extends StatelessWidget {
  final T value;
  final T groupValue;
  final String leading;
  final Widget? title;
  final ValueChanged<T?> onChanged;

  const MyRadioListTile({
    required this.value,
    required this.groupValue,
    required this.onChanged,
    required this.leading,
    this.title,
  });

  @override
  Widget build(BuildContext context) {
    final title = this.title;
    return InkWell(
      onTap: () => onChanged(value),
      child: Container(
        height: 56,
        padding: EdgeInsets.symmetric(horizontal: 16),
        child: Row(
          children: [
            _customRadioButton,
            SizedBox(width: 12),
            if (title != null) title,
          ],
        ),
      ),
    );
  }

  Widget get _customRadioButton {
    final isSelected = value == groupValue;
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: isSelected ? Colors.blue : null,
        borderRadius: BorderRadius.circular(4),
        border: Border.all(
          color: isSelected ? Colors.blue : Colors.grey[300]!,
          width: 2,
        ),
      ),
      child: Text(
        leading,
        style: TextStyle(
          color: isSelected ? Colors.white : Colors.grey[600]!,
          fontWeight: FontWeight.bold,
          fontSize: 18,
        ),
      ),
    );
  }
}

1.在widget中使用它,就像使用普通的RadioListTile一样。

class _MyPageState extends State<MyPage> {
  int _value = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          MyRadioListTile<int>(
            value: 1,
            groupValue: _value,
            leading: 'A',
            title: Text('One'),
            onChanged: (value) => setState(() => _value = value!),
          ),
          MyRadioListTile<int>(
            value: 2,
            groupValue: _value,
            leading: 'B',
            title: Text('Two'),
            onChanged: (value) => setState(() => _value = value!),
          ),
          MyRadioListTile<int>(
            value: 3,
            groupValue: _value,
            leading: 'C',
            title: Text('Three'),
            onChanged: (value) => setState(() => _value = value!),
          ),
        ],
      ),
    );
  }
}
t98cgbkg

t98cgbkg3#

**我用以下逻辑实现了这一点。***如果需要详细解释,请回复 *

import 'package:flutter/material.dart';
    
    class Parent extends StatefulWidget {
      Parent({
        Key key,
      }) : super(key: key);
    
      @override
      _ParentState createState() => _ParentState();
    }
    
    class _ParentState extends State<Parent> {
      int _selectedItem = 0;
    
      selectItem(index) {
        setState(() {
          _selectedItem = index;
          print(selectItem.toString());
        });
      }
    
      @override
      Widget build(BuildContext context) {
        //...YOUR WIDGET TREE HERE
    
        return ListView.builder(
          shrinkWrap: true,
          itemCount: 5,
          itemBuilder: (context, index) {
            return CustomItem(
              selectItem, // callback function, setstate for parent
              index: index,
              isSelected: _selectedItem == index,
              title: index.toString(),
            );
          },
        );
      }
    }
    
    class CustomItem extends StatefulWidget {
      final String title;
      final int index;
      final bool isSelected;
      Function(int) selectItem;
    
      CustomItem(
        this.selectItem, {
        Key key,
        this.title,
        this.index,
        this.isSelected,
      }) : super(key: key);
    
      _CustomItemState createState() => _CustomItemState();
    }
    
    class _CustomItemState extends State<CustomItem> {
      @override
      Widget build(BuildContext context) {
        return Row(
          children: <Widget>[
            Text("${widget.isSelected ? "true" : "false"}"),
            RaisedButton(
              onPressed: () {
                widget.selectItem(widget.index);
              },
              child: Text("${widget.title}"),
            )
          ],
        );
      }
    }
aamkag61

aamkag614#

您可以使用ListView和ListItem创建它,并使用一个局部变量来存储选定的项。并且可以根据变量呈现选定的ListItem。
P.S.让我知道你是否需要代码片段。

[编辑]

正如你所要求的,这里是代码裁剪器,它将向你展示如何维护每个ListView项的状态。
现在你可以玩它,让它成为你想要的方式。如果你只需要一个选中的项目,你可以这样写逻辑。

void main() {
  runApp(new MaterialApp(
    home: new ListItemDemo(),
  ));
}

class ListItemDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("ListItem"),
      ),
      body: new ListView.builder(
          itemCount: 10,
          itemBuilder: (BuildContext context, int index) {
            return new MyListItem(
              title: "Hello ${index + 1}",
            );
          }),
    );
  }
}

class MyListItem extends StatefulWidget {
  final String title;

  MyListItem({this.title});

  @override
  _MyListItemState createState() => new _MyListItemState();
}

class _MyListItemState extends State<MyListItem> {
  bool isSelected;

  @override
  void initState() {
    super.initState();
    isSelected = false;
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new Text("${widget.title} ${isSelected ? "true" : "false"}"),
        new RaisedButton(
          onPressed: () {
            if (isSelected) {
              setState(() {
                isSelected = false;
              });
            } else {
              setState(() {
                isSelected = true;
              });
            }
          },
          child: new Text("Select"),
        )
      ],
    );
  }
}
58wvjzkj

58wvjzkj5#

https://i.stack.imgur.com/Hq0O2.png
这里是自定义单选按钮组按钮小部件。您可以根据您的要求轻松地自定义所有属性。用途:

GroupRadioButton(
              label: [Text("A"), Text("B"), Text("C"), Text("D")],
              padding: EdgeInsets.symmetric(vertical: 10),
              spaceBetween: 5,
              radioRadius: 10,
              color: Const.mainColor,
              onChanged: (listIndex) {
                 print(listIndex);
              },
),

这是GroupRadioButton小部件

import 'package:flutter/material.dart';

class GroupRadioButton extends StatefulWidget {
  GroupRadioButton({
    @required this.label,
    @required this.padding,
    @required this.onChanged,
    this.color = Colors.blue,
    this.radioRadius = 14.0,
    this.spaceBetween = 5.0,
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.crossAxisAlignment = CrossAxisAlignment.start,
  });

  final Color color;
  final List<Widget> label;
  final EdgeInsets padding;
  final Function(int) onChanged;
  final double radioRadius;
  final double spaceBetween;
  final MainAxisAlignment mainAxisAlignment;
  final CrossAxisAlignment crossAxisAlignment;

  @override
  _GroupRadioButtonState createState() => _GroupRadioButtonState();
}

class _GroupRadioButtonState extends State<GroupRadioButton> {
  int selectedIndex = 0;
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        shrinkWrap: true,
        itemCount: widget.label != null ? widget.label.length : 0,
        itemBuilder: (context, index) {
          return LabeledRadio(
            selectedIndex: selectedIndex,
            color: widget.color,
            onChanged: (value) {
              setState(() {
                selectedIndex = value;
                widget.onChanged(value);
                // print(value);
              });
            },
            index: index,
            label: widget.label[index],
            crossAxisAlignment: widget.crossAxisAlignment,
            mainAxisAlignment: widget.mainAxisAlignment,
            radioRadius: widget.radioRadius,
            spaceBetween: widget.spaceBetween,
            padding: widget.padding,
          );
        });
  }
}

class LabeledRadio extends StatelessWidget {
  LabeledRadio({
    @required this.label,
    @required this.index,
    @required this.color,
    //@required this.groupValue,
    //@required this.value,
    @required this.onChanged,
    @required this.radioRadius,
    @required this.padding,
    @required this.spaceBetween,
    @required this.mainAxisAlignment,
    @required this.crossAxisAlignment,
    this.selectedIndex,
  });

  final Color color;
  final int selectedIndex;
  final Widget label;
  final index;
  final EdgeInsets padding;
  //final bool groupValue;
  //final bool value;
  final Function(int) onChanged;
  final double radioRadius;
  final double spaceBetween;
  final MainAxisAlignment mainAxisAlignment;
  final CrossAxisAlignment crossAxisAlignment;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        onChanged(index);
      },
      child: Padding(
        padding: padding,
        child: Row(
          mainAxisAlignment: mainAxisAlignment,
          crossAxisAlignment: crossAxisAlignment,
          children: <Widget>[
            Container(
              decoration: BoxDecoration(
                //color: Const.mainColor,
                shape: BoxShape.circle,
                border: Border.all(color: color, width: 2),
              ),
              padding: EdgeInsets.all(2),
              child: selectedIndex == index
                  ? Container(
                      height: radioRadius,
                      width: radioRadius,
                      decoration: BoxDecoration(
                        color: color,
                        shape: BoxShape.circle,
                      ),
                    )
                  : Container(
                      height: radioRadius,
                      width: radioRadius,
                    ),
            ),
            SizedBox(
              width: spaceBetween,
            ),
            label,
          ],
        ),
      ),
    );
  }
}
mitkmikd

mitkmikd6#

My RadioButton类似于“Radio”小部件:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class RadioButton<T> extends StatefulWidget {
  RadioButton({
    Key key,
    @required this.value,
    @required this.caption,
    @required this.groupValue,
    @required this.onChanged,
  })  : assert(value != null),
        assert(caption != null),
        assert(groupValue != null),
        assert(onChanged != null),
        super(key: key);

  final T value;
  final T groupValue;
  final String caption;
  final Function onChanged;

  @override
  State<StatefulWidget> createState() => _RadioButtonState();
}

class _RadioButtonState extends State<RadioButton> {
  @override
  Widget build(BuildContext context) {
    final bool selected = widget.value == widget.groupValue;

    return GestureDetector(
      onTap: () {
        widget.onChanged(widget.value);
      },
      child: Container(
        width: double.maxFinite,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            color: selected ? Colors.red : Colors.white),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Text(
            widget.caption,
            textAlign: TextAlign.center,
            style: Theme.of(context)
                .textTheme
                .button
                .copyWith(color: selected ? Colors.white : Colors.red),
          ),
        ),
      ),
    );
  }
}
7xllpg7q

7xllpg7q7#

首先创建一个CustomRadioButton类

class CustomRadioButton<T> extends StatelessWidget {
     final T value;
     final T groupValue;
     final String? leading;
     final Widget? title;
     final ValueChanged<T?> onChanged;
     final MaterialColor colorbackground;

 const CustomRadioButton({
super.key,
required this.value,
required this.groupValue,
required this.onChanged,
this.leading,
required this.colorbackground,
this.title,
  });

  @override
 Widget build(BuildContext context) {
// final title = this.title;
return InkWell(
  onTap: () => onChanged(value),
  child: SizedBox(height: 3.h, width: 3.h, child: _customRadioButton),
  );
 }

Widget get _customRadioButton {
final isSelected = value == groupValue;
return Container(
  padding: EdgeInsets.symmetric(horizontal: 1.h, vertical: 1.w),
  decoration: BoxDecoration(
    color: isSelected ? colorbackground : colorbackground,
    shape: BoxShape.circle,
    border: Border.all(
      width: 0.4.h,
      color: isSelected ? Colors.red : Colors.transparent,
      ),
     ),
   );
 }
    }

现在从mainClass调用它
int count = 0;

Container(
  padding: const EdgeInsets.all(1),
  height: 18.h, // Set the desired height for the container
  width: 20.w,
  child: Column(
    mainAxisAlignment: MainAxisAlignment.spaceAround,
    children: [
      CustomRadioButton<int>(
        colorbackground: Colors.orange,
        value: 0,
        groupValue: _value,
        onChanged: (value) {
          setState(() => _value = value!);
          print(_value);
        },
      ),
      CustomRadioButton<int>(
        colorbackground: Colors.green,
        value: 1,
        groupValue: _value,
        onChanged: (value) {
          setState(() => _value = value!);
          print(_value);
        },
      ),
      CustomRadioButton<int>(
        colorbackground: Colors.blue,
        value: 2,
        groupValue: _value,
        onChanged: (value) {
          setState(() => _value = value!);
          print(_value);
        },
      ),
      CustomRadioButton<int>(
        colorbackground: Colors.yellow,
        value: 3,
        groupValue: _value,
        onChanged: (value) {
          setState(() => _value = value!);
          print(_value);
        },
      ),
    ],
  ),
);

8mmmxcuj

8mmmxcuj8#

import 'package:flutter/material.dart';
class CustomRadio extends StatefulWidget {
  @override
  createState() {
    return new CustomRadioState();
  }
}

class CustomRadioState extends State<CustomRadio> {
  List<RadioModel> sampleData = new List<RadioModel>();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    sampleData.add(new RadioModel(true, 'A',0xffe6194B));
    sampleData.add(new RadioModel(false, 'B',0xfff58231));
    sampleData.add(new RadioModel(false, 'C',0xffffe119));
    sampleData.add(new RadioModel(false, 'D',0xffbfef45));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("ListItem"),
      ),
      body: new ListView.builder(
        itemCount: sampleData.length,
        itemBuilder: (BuildContext context, int index) {
          return new InkWell(
            splashColor: Colors.blueAccent,
            onTap: () {
              setState(() {
                sampleData.forEach((element) => element.isSelected = false);
                sampleData[index].isSelected = true;
              });
            },
            child: new RadioItem(sampleData[index]),
          );
        },
      ),
    );
  }
}

class RadioItem extends StatelessWidget {
  final RadioModel _item;
  RadioItem(this._item);
  @override
  Widget build(BuildContext context) {
    return new Container(
      margin: new EdgeInsets.all(15.0),
      child: new Row(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          new Container(
            height: 25.0,
            width: 25.0,
            alignment: Alignment.center,
            child:Container(
            height: 15.0,
            width: 15.0,
              decoration: new BoxDecoration(
              color:Color(_item.colorCode),
              borderRadius: const BorderRadius.all(const Radius.circular(15)),
            )

            ),
            decoration: new BoxDecoration(
              color: Colors.transparent,
              border: new Border.all(
                  width: 3.0,
                  color: _item.isSelected
                      ? Color(_item.colorCode)
                      : Colors.transparent),
              borderRadius: const BorderRadius.all(const Radius.circular(25)),
            ),
          ),
          new Container(
            margin: new EdgeInsets.only(left: 10.0)
          )
        ],
      ),
    );
  }
}

class RadioModel {
  bool isSelected;
  final String buttonText;
  final int colorCode;

  RadioModel(this.isSelected, this.buttonText,this.colorCode);
}
void main() {
  runApp(new MaterialApp(
    home: new CustomRadio(),
  ));
}

点击这里查看put->Here

相关问题