Amine
Amine

Reputation: 1476

Flutter: Is there a widget to flex toggle buttons

So I'm the ToggleButtons introduced in 1.9.1 like this:

Column(
    mainAxisAlignment: MainAxisAlignment.start,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      Padding(padding: EdgeInsets.only(top: 8),),
      Text('Sort By: '),
      Align(
        alignment: Alignment.topLeft,
        child: ToggleButtons(
          borderColor: Color(0xffED7D31),
          selectedBorderColor: Color(0xffED7D31),
          selectedColor: Color(0xffAD7651),
          fillColor: Color(0xffFBE5D6),
          color: Color(0xffBF987E),
          children: <Widget>[
            ...state.sortBy.keys.map((name) => Text(name)).toList()
          ],
          onPressed: (index) => state.toggleSortBy(index),
          isSelected: state.sortBy.values.toList(),
        ),
      ),
    ],
),

This obviously creates a list of button widgets from a map, the problem I'm facing is that I'm seeing the following warning in my screen

Right overflowed by X pixels

So my question is simply whether there is a way to "flex" the buttons like in CSS, meaning when the number of buttons exceeds the screen size, the buttons would automatically start from the next line.

EDIT:

The state.sortBy is just a Map where I store the texts for my widgets alongside their selected values:

LinkedHashMap<String,bool> sortBy = LinkedHashMap.from({
    'Ascending' : true,
    'Descending' : false,
})

Upvotes: 3

Views: 2575

Answers (1)

J. S.
J. S.

Reputation: 9625

So this was a bit of work, but I've made a Widget that I've called WrapIconToggleButtons and that should fit what you are looking for. It's rudimentary but you can customize it as you see fit. Please take a look:

How to use (similar to ToggleButtons)

class Main extends StatefulWidget {
  @override
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {
  List<bool> isSelected = [
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
  ];

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        child: WrapToggleIconButtons(
          iconList: [
            Icons.ac_unit,
            Icons.shopping_cart,
            Icons.shopping_cart,
            Icons.done,
            Icons.fiber_pin,
            Icons.sentiment_satisfied,
            Icons.looks_6,
            Icons.apps,
          ],
          isSelected: isSelected,
          onPressed: (int index) {
            setState(() {
              for (int buttonIndex = 0; buttonIndex < isSelected.length; buttonIndex++) {
                if (buttonIndex == index) {
                  isSelected[buttonIndex] = !isSelected[buttonIndex];
                } else {
                  isSelected[buttonIndex] = false;
                }
              }
            });
          },
        ),
      ),
    );
  }
}

WrapToggleIconButtons Widget

class WrapToggleIconButtons extends StatefulWidget {
  final List<IconData> iconList;
  final List<bool> isSelected;
  final Function onPressed;

  WrapToggleIconButtons({
    @required this.iconList,
    @required this.isSelected,
    @required this.onPressed,
  });

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

class _WrapToggleIconButtonsState extends State<WrapToggleIconButtons> {
  int index;

  @override
  Widget build(BuildContext context) {
    assert(widget.iconList.length == widget.isSelected.length);
    index = -1;
    return Wrap(
      children: widget.iconList.map((IconData icon){
        index++;
        return IconToggleButton(
          active: widget.isSelected[index],
          icon: icon,
          onTap: widget.onPressed,
          index: index,
        );
      }).toList(),
    );
  }
}

class IconToggleButton extends StatelessWidget {
  final bool active;
  final IconData icon;
  final Function onTap;
  final int width;
  final int height;
  final int index;

  IconToggleButton({
    @required this.active,
    @required this.icon,
    @required this.onTap,
    @required this.index,
    this.width,
    this.height,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width ?? 60,
      height: height ?? 60,
      child: InkWell(
        child: Icon(icon,
          color: active ? Theme.of(context).accentColor : Theme.of(context).disabledColor,
        ),
        onTap: () => onTap(index),
      ),
    );
  }
}

Upvotes: 2

Related Questions