首页 > 解决方案 > 如何在 Flutter 中设置 CustomRadioButton 中的图标?

问题描述

我是新手,我想根据两种性别设置图标/图像。任何人都可以请给我帮助!
我用过这个包custom_radio_grouped_button:

Container(
                      child: CustomRadioButton(
                        elevation: 0,
                        absoluteZeroSpacing: false,
                        unSelectedColor: Theme.of(context).canvasColor,
                        buttonLables: [
                          'Male',
                          'Female',
                        ],
                        buttonValues: [
                          "MALE",
                          "FEMALE",
                        ],
                        buttonTextStyle: ButtonTextStyle(
                            textStyle: TextStyle(fontSize: 16)),
                        radioButtonValue: (value) {
                          print(value);
                        },
                        selectedColor: Colors.green,
                      ),
                    ),

标签: flutterdart

解决方案


正如 Theophile 所说,custom_radio_grouped_button包目前不允许添加图标或图像。

但是,如果您想利用此包提供的其他功能但又不想重新发明轮子,则可以将包的代码复制到项目的新文件中,并进行您需要的编辑需要让它按你的预期工作。

尽管我不建议将此作为一般做法,但鉴于我无法轻松找到另一个小部件来解决此问题,并且 custom_radio_grouped_button 的实现相对较小,您可以在这种情况下采用这种方法。

作为一个例子,我已经这样做了,这里是修改后的代码。您可以将此代码复制/粘贴到项目的本地文件中(可能命名为custom_radio_button_shape.dart):

import 'package:flutter/material.dart';

// ignore: must_be_immutable
class CustomRadioButtonShape<T> extends StatefulWidget {
  CustomRadioButtonShape({
    this.buttonWidgets,
    this.buttonValues,
    this.buttonTextStyle = const ButtonTextStyleShape(),
    this.autoWidth = false,
    this.radioButtonValue,
    this.unSelectedColor,
    this.unSelectedBorderColor,
    this.padding = 3,
    this.spacing = 0.0,
    this.selectedColor,
    this.selectedBorderColor,
    this.height = 35,
    this.width = 100,
    this.enableButtonWrap = false,
    this.horizontal = false,
    this.enableShape = false,
    this.elevation = 10,
    this.defaultSelected,
    this.customShape,
    this.absoluteZeroSpacing = false,
    this.wrapAlignment = WrapAlignment.start,
  })  : assert(buttonWidgets.length == buttonValues.length,
  "Button values list and button lables list should have same number of eliments "),
        assert(unSelectedColor != null, "Unselected color cannot be null"),
        assert(buttonValues.toSet().length == buttonValues.length,
        "Multiple buttons with same value cannot exist"),
  // assert(buttonLables.toSet().length == buttonLables.length,
  //     "Multiple buttons label wth same value cannot exist"),
        assert(selectedColor != null, "Selected color cannot be null");

  ///Orientation of the Button Group
  final bool horizontal;

  ///Values of button
  final List<T> buttonValues;

  ///This option will make sure that there is no spacing in between buttons
  final bool absoluteZeroSpacing;

  ///Default value is 35
  final double height;
  double padding;

  ///Spacing between buttons
  double spacing;

  ///Default selected value
  final T defaultSelected;

  ///Only applied when in vertical mode
  ///This will use minimum space required
  ///If enables it will ignore [width] field
  final bool autoWidth;

  ///Use this if you want to keep width of all the buttons same
  final double width;

  final List<Widget> buttonWidgets;

  ///Styling class for label
  final ButtonTextStyleShape buttonTextStyle;

  final void Function(T) radioButtonValue;

  ///Unselected Color of the button
  final Color unSelectedColor;

  ///Selected Color of button
  final Color selectedColor;

  ///Unselected Color of the button border
  final Color unSelectedBorderColor;

  ///Selected Color of button border
  final Color selectedBorderColor;

  /// A custom Shape can be applied (will work only if [enableShape] is true)
  final ShapeBorder customShape;

  ///alignment for button when [enableButtonWrap] is true
  final WrapAlignment wrapAlignment;

  /// This will enable button wrap (will work only if orientation is vertical)
  final bool enableButtonWrap;

  ///if true button will have rounded corners
  ///If you want custom shape you can use [customShape] property
  final bool enableShape;
  final double elevation;

  _CustomRadioButtonShapeState createState() => _CustomRadioButtonShapeState();
}

class _CustomRadioButtonShapeState extends State<CustomRadioButtonShape> {
  Widget _currentSelectedWidget;

  Color borderColor(index) => (_currentSelectedWidget == widget.buttonWidgets[index] ? widget.selectedBorderColor : widget.unSelectedBorderColor) ?? Theme.of(context).primaryColor;

  @override
  void initState() {
    super.initState();
    if (widget.defaultSelected != null) {
      if (widget.buttonValues.contains(widget.defaultSelected)) {
        int index = widget.buttonValues.indexOf(widget.defaultSelected);
        _currentSelectedWidget = widget.buttonWidgets[index];
      } else
        throw Exception("Default Value not found in button value list");
    }
  }

  List<Widget> _buildButtonsColumn() {
    return widget.buttonValues.map((e) {
      int index = widget.buttonValues.indexOf(e);
      return Padding(
        padding: EdgeInsets.all(widget.padding),
        child: Card(
          margin: EdgeInsets.all(widget.absoluteZeroSpacing ? 0 : 4),
          color: _currentSelectedWidget == widget.buttonWidgets[index]
              ? widget.selectedColor
              : widget.unSelectedColor,
          elevation: widget.elevation,
          shape: widget.enableShape
              ? widget.customShape == null
              ? RoundedRectangleBorder(
            borderRadius: BorderRadius.all(Radius.circular(50)),
          )
              : widget.customShape
              : null,
          child: Container(
            height: widget.height,
            child: MaterialButton(
              shape: widget.enableShape
                  ? widget.customShape == null
                  ? OutlineInputBorder(
                borderSide: BorderSide(
                    color: borderColor(index), width: 1),
                borderRadius: BorderRadius.all(Radius.circular(20)),
              )
                  : widget.customShape
                  : OutlineInputBorder(
                borderSide: BorderSide(
                    color: borderColor(index), width: 1),
                borderRadius: BorderRadius.zero,
              ),
              onPressed: () {
                widget.radioButtonValue(e);
                setState(() {
                  _currentSelectedWidget = widget.buttonWidgets[index];
                });
              },
              child: Center(
                child: widget.buttonWidgets[index],/*Text(
                  widget.buttonLables[index],
                  textAlign: TextAlign.center,
                  overflow: TextOverflow.ellipsis,
                  maxLines: 1,
                  style: widget.buttonTextStyle.textStyle.copyWith(
                    color: _currentSelectedLabel == widget.buttonLables[index]
                        ? widget.buttonTextStyle.selectedColor
                        : widget.buttonTextStyle.unSelectedColor,
                  ),
                ),*/
              ),
            ),
          ),
        ),
      );
    }).toList();
  }

  List<Widget> _buildButtonsRow() {
    return widget.buttonValues.map((e) {
      int index = widget.buttonValues.indexOf(e);
      return Card(
        margin: EdgeInsets.all(widget.absoluteZeroSpacing ? 0 : 4),
        color: _currentSelectedWidget == widget.buttonWidgets[index]
            ? widget.selectedColor
            : widget.unSelectedColor,
        elevation: widget.elevation,
        shape: widget.enableShape
            ? widget.customShape == null
            ? RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(50)),
        )
            : widget.customShape
            : null,
        child: Container(
          height: widget.height,
          width: widget.autoWidth ? null : widget.width,
          constraints: BoxConstraints(maxWidth: 250),
          child: MaterialButton(
            shape: widget.enableShape
                ? widget.customShape == null
                ? OutlineInputBorder(
              borderSide: BorderSide(
                  color: borderColor(index), width: 1),
              borderRadius: BorderRadius.all(Radius.circular(20)),
            )
                : widget.customShape
                : OutlineInputBorder(
              borderSide: BorderSide(
                  color: borderColor(index), width: 1),
              borderRadius: BorderRadius.zero,
            ),
            onPressed: () {
              widget.radioButtonValue(e);
              setState(() {
                _currentSelectedWidget = widget.buttonWidgets[index];
              });
            },
            child: Center(
              child: widget.buttonWidgets[index],/*Text(
                widget.buttonLables[index],
                textAlign: TextAlign.center,
                overflow: TextOverflow.ellipsis,
                maxLines: 1,
                style: widget.buttonTextStyle.textStyle.copyWith(
                  color: _currentSelectedLabel == widget.buttonLables[index]
                      ? widget.buttonTextStyle.selectedColor
                      : widget.buttonTextStyle.unSelectedColor,
                ),
              ),*/
            ),
          ),
        ),
      );
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.absoluteZeroSpacing) {
      widget.spacing = 0;
      widget.padding = 0;
    }
    return _buildRadioButtons();
  }

  _buildRadioButtons() {
    if (widget.horizontal)
      return Container(
        height: widget.height * (widget.buttonWidgets.length * 1.5) +
            widget.padding * 2 * widget.buttonWidgets.length,
        child: Center(
          child: CustomListViewSpacingShape(
            spacing: widget.spacing,
            scrollDirection: Axis.vertical,
            children: _buildButtonsColumn(),
          ),
        ),
      );
    if (!widget.horizontal && widget.enableButtonWrap)
      return Container(
        child: Center(
          child: Wrap(
            spacing: widget.spacing,
            direction: Axis.horizontal,
            alignment: widget.wrapAlignment,
            children: _buildButtonsRow(),
          ),
        ),
      );
    if (!widget.horizontal && !widget.enableButtonWrap)
      return Container(
        height: widget.height + widget.padding * 2,
        child: Center(
          child: CustomListViewSpacingShape(
            spacing: widget.spacing,
            scrollDirection: Axis.horizontal,
            children: _buildButtonsRow(),
          ),
        ),
      );
  }
}

class ButtonTextStyleShape {
  ///Selected color of Text
  final Color selectedColor;

  ///Unselected color of Text
  final Color unSelectedColor;
  final TextStyle textStyle;

  const ButtonTextStyleShape({
    this.selectedColor = Colors.white,
    this.unSelectedColor = Colors.black,
    this.textStyle = const TextStyle(),
  });
}

class CustomListViewSpacingShape extends StatelessWidget {
  final List<Widget> children;
  final double spacing;
  final Axis scrollDirection;
  CustomListViewSpacingShape(
      {@required this.children,
        this.spacing = 0.0,
        this.scrollDirection = Axis.vertical});

  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: scrollDirection,
      children: children
          .map((c) => Container(
        padding: EdgeInsets.all(spacing),
        child: c,
      ))
          .toList(),
    );
  }
}

然后您可以按如下方式使用它(对于本示例,我还使用包https://pub.dev/packages/flutter_icons,其中包含大量精美图标,但如果需要,您可以使用自己的自定义图像),并且这是结果

CustomRadioButtonShape(
  elevation: 0,
  absoluteZeroSpacing: true,
  unSelectedColor: Theme.of(context).canvasColor,
  buttonWidgets: [
    Row(
      children: [
        Icon(
          FontAwesome.male,
          size: 15,
        ),
        Padding(
          padding: const EdgeInsets.only(left: 5),
          child: Text('Male'),
        ),
      ],
    ),
    Row(
      children: [
        Icon(
          FontAwesome.female,
          size: 15,
        ),
        Padding(
          padding: const EdgeInsets.only(left: 5),
          child: Text('Female'),
        ),
      ],
    ),
  ],
  buttonValues: [
    "MALE",
    "FEMALE",
  ],
  buttonTextStyle: ButtonTextStyleShape(
    selectedColor: Colors.white,
    unSelectedColor: Colors.black,
    textStyle: TextStyle(fontSize: 16)
  ),
  radioButtonValue: (value) {
    print(value);
  },
  selectedColor: Theme.of(context).accentColor,
),

希望这可以帮助。


推荐阅读