Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the background color of raised button dynamically in onPressed()

I have a list of Raised buttons, I want the background color of the selected button to change in its onPressed()

I tried changing the color in setState but it doesn't do anything.

This is the function that generates the list of Buttons

List<Widget> _makeZoneList(List<Zone> zones) {
    List<Widget>Buttons = new List();
    for (int i = 0; i < zones.length; i++) {
      Buttons.add(RaisedButton(
        color: zones[i].isSelected ? AppColors.primaryColor : AppColors.white,
        onPressed: () {
          setState(() {
            if (zones[i].isSelected){
              zones[i].isSelected = false;
            }
            else{
              zones[i].isSelected = true;
            }
            print(zones[i].isSelected.toString());
          });
        },
        child: Text(zones.elementAt(i).text)
      ));
    }
    return Buttons;
  }

This is where I call the function

Widget _zoneBody() {
    return Padding(
        padding: EdgeInsets.all(32),
        child: StreamBuilder<List<Zone>>(
            stream: GetterBloc.zonesStream,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return new Container();
              } else {
                if (snapshot.hasData) {
                     return Wrap(
                          spacing: 6.0, // gap between adjacent chips
                          children: _makeZoneList(snapshot.data));

                } else {
                  return new Container();
                }
              }
            }));
  }

When I press any button, its isSelected value changes but the background doesn't change accordingly

like image 630
Ghada Shebl Avatar asked Apr 10 '19 22:04

Ghada Shebl


2 Answers

Updated answer (ElevatedButton)

Since RaisedButton is now deprecated, use ElevatedButton:

enter image description here

Code:

class _MyState extends State<MyPage> {
  bool _flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () => setState(() => _flag = !_flag),
          child: Text(_flag ? 'Red' : 'Green'),
          style: ElevatedButton.styleFrom(
            primary: _flag ? Colors.red : Colors.teal, // This is what you need!
          ),
        ),
      ),
    );
  }
}

Old answer

It was difficult to implement your code because of undefined classes and variable, however I created a small example which will help you what you are looking for.

List<bool> _list = [true, false, true, false];

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("Title")),
    body: ListView(children: _buildButtons()),
  );
}

List<Widget> _buildButtons() {
  List<Widget> listButtons = List.generate(_list.length, (i) {
    return RaisedButton(
      color: _list[i] ? Colors.green : Colors.red,
      onPressed: () {
        setState(() {
          _list[i] = !_list[i];
        });
      },
      child: Text("Button #${i}"),
    );
  });
  return listButtons;
}

Output:

enter image description here

like image 71
CopsOnRoad Avatar answered Sep 22 '22 18:09

CopsOnRoad


Unless I'm mistaken, what you're trying to do is already handled by flutter. I think all you have to do is set the hightlightColor of the button and when it is pressed it will change to that color. And you could set this into the theme for your entire application so that all buttons behave the same rather then setting it for each individual button.

However, there's also a reason why what you're doing isn't working. You haven't included quite enough code for me to tell, but I believe the reason why what you're doing isn't working is that you have a List of data that you're mutating when the button is pressed (i.e. zones[i].isSelected = false;). You're doing that in a setState, but the way that flutter checks whether something needs rebuilding is by doing an equality compare on the State's members (i.e. it will check whether zones == zones).

Because 'zones' is just a list, and is actually the same list in for the old state and the new state, flutter will assume nothing has changed and won't bother rebuilding.

There's two easy ways to get around this. One would be to make a copy of the list each time it is modified and set the zones member to that, so that when flutter does the compare old.zones != new.zones. The other way would be to keep a separate object that you change each time the list is modified (I tend to use an integer called changeCounter that I increment each time the list changes) as that way you can 'fool' flutter into rebuilding.

like image 41
rmtmckenzie Avatar answered Sep 22 '22 18:09

rmtmckenzie