Flutter: GetX Obx() could not rebuild ListView items

Issue

I am working on a simple ListView. I managed to update the list view with the correct data, see items which is <String>[].obs, when it got populated the data, I can see the list view is populated.

However, it seems after the list view items are built, they are not observing my selected change, which is 0.obs. From the debugging code, I can see the selected got updated, the title changes accordingly, but the list view items did not rebuild (and hence change color), and not reflecting if they are being selected.

Please help me to understand why selected change did not trigger list item rebuild, and how to fix. Thanks!

My home_controller.dart:

import 'package:get/get.dart';

class HomeController extends GetxController {
  final loading = true.obs;
  final items = <String>[].obs;
  final selected = 0.obs;

  final count = 0.obs;
  @override
  void onInit() {
    fetchItems();
    super.onInit();
  }

  Future<void> fetchItems() async {
    loading.value = true;
    Future.delayed(const Duration(seconds: 5), () {
      final newItems = ['abc', 'def', 'ghij', 'klmnopq'];
      items.assignAll(newItems);
      loading.value = false;
    });
  }

  void onHover(int index) {
    selected.value = index;
    print('onHover: $index');
  }
}

And my home_view.dart:

import 'package:flutter/material.dart';

import 'package:get/get.dart';

import '../controllers/home_controller.dart';

class HomeView extends GetView<HomeController> {
  const HomeView({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title:
            Obx(() => Text('HomeView: selected ${controller.selected.value}')),
        centerTitle: true,
      ),
      body: Obx(() => Center(
            child: controller.loading.value
                ? const CircularProgressIndicator()
                : ListView.builder(
                    itemCount: controller.items.length,
                    itemBuilder: (BuildContext context, int index) {
                      final color = controller.selected.value == index
                          ? Colors.green
                          : Colors.grey;
                      return MouseRegion(
                        onHover: (event) {
                          controller.onHover(index);
                        },
                        onExit: ((event) {
                          final selected = controller.selected.value;
                          print(
                              'exiting: $index, current selected: ${selected}');
                        }),
                        child: ListTile(
                          leading:
                              Container(width: 40, height: 40, color: color),
                          title: Text(controller.items[index]),
                        ),
                      );
                    },
                  ),
          )),
    );
  }
}

Solution

I believe wrapping your MouseRegion with another Obx would solve it for you. It being inside another builder will not make it able to be observed by the outer Obx

Answered By – Ivo

Answer Checked By – David Marino (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *