Home > Mobile >  GetX UI state not changing on ListTile
GetX UI state not changing on ListTile

Time:10-05

I have a list of objects, but I want to change the state of one object to "isLoading" where it will have a different title, etc.

I'm building my list view:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: scaffoldKey,
        body: Obx(() => buildListView(context)));
  }

  Widget buildListView(BuildContext context) {
    return ListView.builder(
        itemCount: controller.saveGames.length,
        itemBuilder: (context, index) {
          final saveGame = controller.saveGames.elementAt(index);

          return saveGame.isLoading
              ? buildListTileIsLoading(context, saveGame)
              : buildListTile(context, saveGame);
        });
  }

  ListTile buildListTile(BuildContext context, SaveGame saveGame) {
    return ListTile(
      onTap: () => controller.process(saveGame)
    );
  }

The controller:

class SaveGameController extends GetxController {

  final RxList<SaveGame> saveGames = <SaveGame>[].obs;
  
  void process(SaveGame saveGame) {
    saveGame.working = true;

    update();
  }
  
}

Where have I gone wrong here?

edits: Added more code

CodePudding user response:

So despite the fact, I'm only updating one object in the list and not modifying the content of the list (adding/removing objects) I still need to call saveGames.refresh();

An oversight on my end didn't think you'd need to refresh the entire list if you're just changing the property on one of the objects.

Good to know :)

CodePudding user response:

update() is used with GetBuilder()

obs() is used with obx()

you need to make a change on list to update widgets

enter image description here

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      onInit: () {
        Get.lazyPut(() => SaveGameController());
      },
      home: const HomePage(),
    );
  }
}

class HomePage extends GetView<SaveGameController> {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(), body: Obx(() => buildListView(context)));
  }

  Widget buildListView(BuildContext context) {
    return ListView.builder(
        itemCount: controller.saveGames.length,
        itemBuilder: (context, index) {
          final saveGame = controller.saveGames.elementAt(index);

          return buildListTile(context, saveGame);
        });
  }

  ListTile buildListTile(BuildContext context, SaveGame saveGame) {
    return ListTile(
        tileColor: saveGame.working ? Colors.red : Colors.yellow,
        title: Text(saveGame.name),
        onTap: () => controller.process(saveGame));
  }
}

class SaveGameController extends GetxController {
  final RxList<SaveGame> saveGames = <SaveGame>[
    SaveGame(id: 0, name: 'a', working: false),
    SaveGame(id: 1, name: 'b', working: false),
    SaveGame(id: 2, name: 'c', working: false)
  ].obs;

  void process(SaveGame saveGame) {
    final index = saveGames.indexWhere((element) => element.id == saveGame.id);
    saveGames
        .replaceRange(index, index   1, [saveGame.copyWith(working: true)]);
  }
}

class SaveGame {
  final int id;
  final String name;
  final bool working;
  SaveGame({required this.id, required this.name, required this.working});
  SaveGame copyWith({int? id, String? name, bool? working}) {
    return SaveGame(
        id: id ?? this.id,
        name: name ?? this.name,
        working: working ?? this.working);
  }
}
  • Related