'Flutter change button color when clicked in a list of buttons

I have a list of buttons in my app and each button is supposed to filter a list of items. All buttons have the same color, I want such that only one button has an active color no matter which button is clicked. Currently I end up changing the color of all buttons when I click one button.

Here is my code

final blueColors = const Color(0xff295a7c);
final blueShades = const Color(0xffccdef2);
final blackColors = const Color(0xff000000);
final whiteColors = const Color(0xffffffff);


Padding(
  padding: const EdgeInsets.all(10),
  child: SizedBox(
    height: 40,
    child: ListView(
      shrinkWrap: true,
      scrollDirection: Axis.horizontal,
      children: [
        Padding(
          padding: const EdgeInsets.all(3),
          child: Obx(
            () => TextButton(
              onPressed: () {
                controller.changeButton();
              },
              child: Text(
                'All',
                style: theme.textTheme.bodyText2!.copyWith(
                  color: controller.whenPressed.value == true ? whiteColors : blackColors,
                  fontSize: 13,
                  fontWeight: FontWeight.w400,
                ),
              ),
              style: TextButton.styleFrom(
                primary: Colors.white,
                backgroundColor:
                    controller.whenPressed.value == true
                        ? blueColors
                        : blueShadeColors,
                onSurface: Colors.grey,
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  ),
                ),
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(3),
          child: Obx(
            () => TextButton(
              onPressed: () {
                controller.changeButton();
              },
              child: Text(
                'option 2',
                style: theme.textTheme.bodyText2!.copyWith(
                  color: controller.whenPressed.value == true ? whiteColors : blackColors,
                  fontSize: 13,
                  fontWeight: FontWeight.w400,
                ),
              ),
              style: TextButton.styleFrom(
                primary: Colors.white,
                backgroundColor:
                    controller.whenPressed.value == true
                        ? blueColors
                        : blueShadeColors,
                onSurface: Colors.grey,
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  ),
                ),
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(3),
          child: Obx(
            () => TextButton(
              onPressed: () {
                controller.changeButton();
              },
              child: Text(
                'option 3',
                style: theme.textTheme.bodyText2!.copyWith(
                  color: controller.whenPressed.value == true ? whiteColors : blackColors,
                  fontSize: 13,
                  fontWeight: FontWeight.w400,
                ),
              ),
              style: TextButton.styleFrom(
                primary: Colors.white,
                backgroundColor:
                    controller.whenPressed.value == true
                        ? blueColors
                        : blueShadeColors,
                onSurface: Colors.grey,
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  ),
                ),
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(3),
          child: Obx(
            () => TextButton(
              onPressed: () {
                controller.changeButton();
              },
              child: Text(
                'option 4',
                style: theme.textTheme.bodyText2!.copyWith(
                  color: controller.whenPressed.value == true ? whiteColors : blackColors,
                  fontSize: 13,
                  fontWeight: FontWeight.w400,
                ),
              ),
              style: TextButton.styleFrom(
                primary: Colors.white,
                backgroundColor:
                    controller.whenPressed.value == true
                        ? blueColors
                        : blueShadeColors,
                onSurface: Colors.grey,
                shape: const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  ),
                ),
              ),
            ),
          ),
        ),                                     
      ],
    ),
  ),
),  

I am using Getx for statemananegement. Here is my controller code.

var whenPressed = false.obs;

void changeButton() {
    whenPressed.value = !whenPressed.value;
    update();
}

How can I modify it such that only one button will get the active button color on any click event



Solution 1:[1]

I found a way to do what to change the button color of a single button when pressed.

I added this code to the controller

var _selectedButton = 0.obs;

List<String> categories = [
    'All',
    'Option 1',
    'Option 2',
    'Option 3',
    'Option 4',
    'Option 5',
  ];

Then added this method

int changeButton(int index) {
  _selectedButton.value = index;
  update();
  return _selectedButton.value;
}

Finally I replaced the view with this code

ListView.separated(
  shrinkWrap: true,
  scrollDirection: Axis.horizontal,
  itemBuilder: (context, index) {
    return   Obx(
    () => TextButton(
      onPressed: () {
        controller.changeButton(index);
      },
      child: Text(
        controller.categories[index],
        style: theme.textTheme.bodyText2!.copyWith(
          color: controller._selectedButton.value == index
              ? whiteColor
              : blackColor,
          fontSize: 13,
          fontWeight: FontWeight.w400,
        ),
      ),
      style: TextButton.styleFrom(
        primary: Colors.white,
        backgroundColor:
            controller._selectedButton.value == index
                ? blueColor
                : blueShadeColor,
        onSurface: Colors.grey,
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.all(
            Radius.circular(20),
          ),
        ),
      ),
    ),
  );
  },
  itemCount: controller.categories.length,
  separatorBuilder: (context, index) =>
      const SizedBox(width: 5),
),

Solution 2:[2]

The problem your all buttons use same controller. I guess you have code like this in your page.

final controller = Get.put(Controller());
// maybe you put controller on another area then you used like this
//final controller = Get.find<Controller>();    

use different controller for your buttons, remember if you do not set tag to controller, they will not be different

final controllerAll = Get.put(Controller(), tag: "ALL");
final controllerOption1 = Get.put(Controller(), tag: "OPTION1");
final controllerOption2 = Get.put(Controller(), tag: "OPTION2");
final controllerOption3 = Get.put(Controller(), tag: "OPTION3");

Therefore when you click any button, only that button will have active color.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kevnlan
Solution 2 Ugur Aydogdu