1

I'm trying to use GetX to change the color of a selected "Category", that comes from a list of categories. Currently, in the background the values are changing as expected, but the UI is not refreshed.

I tried both GetBuilder and Obx to have my UI updated, but with same outcome. Please see the code bellow:

import 'package:flutter/material.dart';

class Category {
  String name;
  IconData icon;
  Set<SubCategory> subcategories;

  Category({
    required this.name,
    required this.icon,
    required this.subcategories,
  });
}

class SubCategory {
  String name;
  IconData icon;

  SubCategory({
    required this.name,
    required this.icon,
  });
}

import 'package:annual_budget/backend/model/spending_categories.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class ExpensesController extends GetxController {
  var expenseCategories = [].obs;
  var expenseSubcategories = [].obs;
  var selectedCategoryName = ''.obs;
  var selectedSubcategoryName = ''.obs;

  @override
  void onInit() {
    super.onInit();
    expenseCategories.value = [
      Category(
        icon: Icons.all_inclusive_rounded,
        name: 'Everyday',
        subcategories: {
          SubCategory(icon: Icons.local_grocery_store, name: 'Groceries'),
          SubCategory(icon: Icons.restaurant, name: 'Restaurant'),
          SubCategory(icon: Icons.delivery_dining, name: 'Food Order'),
        },
      ),
      Category(
        icon: Icons.travel_explore,
        name: 'Travel',
        subcategories: {
          SubCategory(
              icon: Icons.airplane_ticket_outlined, name: 'Transportation'),
          SubCategory(icon: Icons.food_bank_rounded, name: 'Food'),
          SubCategory(icon: Icons.house, name: 'Accomodation'),
        },
      ),
      Category(
        icon: Icons.pets_rounded,
        name: 'Pet',
        subcategories: {
          SubCategory(icon: Icons.food_bank, name: 'Food'),
          SubCategory(icon: Icons.medical_services, name: 'Veterinary'),
        },
      ),
    ];
  }

  void setSubcategories(Set<SubCategory> subcategories, String categoryName) {
    print(selectedCategoryName);
    selectedCategoryName.value = categoryName;
    expenseSubcategories.value = subcategories.toList();
    print(selectedCategoryName);
    refresh();
  }
}

In the above print statements, the value changes as expected, but without propagating to the UI

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class NewExpenseScreen extends StatelessWidget {
  static const String route = 'new_expense_screen2';
  final ExpensesController exc = Get.put(ExpensesController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        leading: MaterialButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Icon(Icons.arrow_back_ios_new_rounded),
        ),
        title: const Text('Add a new Expense'),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Expanded(
              child: Obx(
                () => ListView.builder(
                    itemCount: exc.expenseCategories.length,
                    itemBuilder: (context, index) {
                      Category category = exc.expenseCategories[index];

                      return MaterialButton(
                        color: category.name == exc.selectedCategoryName.value
                            ? ThemeData.dark().colorScheme.secondary
                            : ThemeData.dark().colorScheme.background,
                        onPressed: () {
                          exc.setSubcategories(
                              category.subcategories, category.name);

                          print(
                              'category ${category.name} isSelected: ${category.name == exc.selectedCategoryName.value}  ');
                          FocusManager.instance.primaryFocus?.unfocus();
                        },
                        child: Padding(
                          padding: const EdgeInsets.symmetric(vertical: 10),
                          child: Column(
                            children: [
                              Icon(
                                category.icon,
                                color: category.name ==
                                        exc.selectedCategoryName.value
                                    ? Colors.black
                                    : Colors.white,
                              ),
                              Text(
                                category.name,
                                style: TextStyle(
                                  color: category.name ==
                                          exc.selectedCategoryName.value
                                      ? Colors.black
                                      : Colors.white,
                                ),
                              )
                            ],
                          ),
                        ),
                      );
                    }),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

The print statement from the OnPressed shows the desired changes, but the UI is still not refreshed until I do a hot reload.

Headake
  • 33
  • 6

1 Answers1

1

Please check out below code.

void setSubcategories(Set<SubCategory> subcategories, String categoryName) {
    print(selectedCategoryName);
    selectedCategoryName.value = categoryName;
    expenseSubcategories.value = subcategories.toList();
    print(selectedCategoryName);
    expenseCategories.refresh();
}

You have to refresh the expenseCategories list in the setSubcategories method.

When you need to update multiple lists, you should use getbuilder.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Ruchit Soni
  • 166
  • 5
  • 1
    This work, thanks. I would like a little more information on why using only refresh() does not work and also on why should I use GetBuilder and not Obx. – Headake Mar 07 '23 at 11:55
  • Nothing happens if you only use the refresh method. If you want to update your list using obx, you have to use list.refresh method. If you will use getbuilder instead of obx, you only have to write update method.Now you don't have to write refresh method for each list.That is why, when working with a multiple list, getbuilder is recommended. – Ruchit Soni Mar 07 '23 at 13:01