如何在 Flutter 中的 ListView 中的数据发生变化时仅更新其中一个 Widget?

问题描述 投票:0回答:1
class ListNumbersPage extends GetView<MyController> {
  final colors = [
    Colors.red,
    Colors.green,
    Colors.pinkAccent,
    Colors.blue,
    Colors.grey,
    Colors.cyan,
  ];
  final random = Random();

  @override
  Widget build(BuildContext context) {
    Get.put(MyController());

    return Scaffold(
      appBar: AppBar(title: const Text('ListNumbersPage')),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: controller.listOfFiles.length,
              itemBuilder: (_, index) {
                final currentFile = controller.listOfFiles[index];
                return Container(
                  padding: const EdgeInsets.symmetric(vertical: 32),
                  color: colors[random.nextInt(colors.length)],
                  child: Row(
                    children: [
                      Obx(
                        () {
                          MyLogs.warning('UPDATED INDEX : $index');
                          return MyIconButton(
                            onTap: () {
                              doLike(controller.listOfSelection ?? [], currentFile.value.fileId, index);
                            },
                            iconData: FontAwesomeIcons.solidHeart,
                            color: isExist(controller.listOfSelection ?? [], currentFile.value.fileId, index)
                                ? isLiked(controller.listOfSelection ?? [], currentFile.value.fileId)
                                    ? AppColor.redDark
                                    : AppColor.white
                                : AppColor.white,
                          );
                        },
                      ),
                      Text(controller.listOfFiles[index].value.fileId),
                    ],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

bool isExist(List<Rx<LikeModel>> listOfSelection, String fileId, int index) {
  try {
    if (listOfSelection.length >= index) {
      final item = listOfSelection.firstWhereOrNull((e) => e.value.fileId == fileId);
      return item != null;
    } else {
      return false;
    }
  } catch (e) {
    MyLogs.debug(e.toString());
    return false;
  }
}

bool isLiked(List<Rx<LikeModel>> listOfSelection, String fileId) {
  try {
    return listOfSelection.firstWhere((e) => e.value.fileId == fileId).value.isLiked;
  } catch (e) {
    MyLogs.debug(e.toString());
    return false;
  }
}

void doLike(List<Rx<LikeModel>> listOfSelection, String fileId, int index) {
  try {
    final item = listOfSelection.firstWhere((element) => element.value.fileId == fileId);
    final index = listOfSelection.indexOf(item);
    final isLiked = item.value.isLiked;

    listOfSelection[index].value = item.value.copyWith(
      isLiked: !isLiked,
    );
  } catch (e) {
    MyLogs.debug(e.toString());
  }
}

class MyController extends GetxController {
  final listOfFiles = [
    "IMAGE001",
    "IMAGE002",
    "IMAGE003",
    "IMAGE004",
    "IMAGE005",
    "IMAGE006",
    "IMAGE007",
    "IMAGE008",
    "IMAGE009",
    "IMAGE010",
  ].map((e) => LikeModel(e, false).obs).toList();

  List<Rx<LikeModel>>? listOfSelection;

  @override
  void onInit() {
    listOfSelection = listOfFiles;
    super.onInit();
  }
}

class LikeModel {
  String fileId;
  bool isLiked;

  LikeModel(this.fileId, this.isLiked);

  LikeModel copyWith({
    String? fileId,
    bool? isLik
  }) {
    return LikeModel(
      fileId ?? this.fileId,
      isLiked ?? this.isLiked,
    );
  }
}

我在 Flutter 应用程序中遇到一个问题,其中有一个 ListView 显示项目列表,每个项目都包含一个“like”按钮。当我按下特定项目的“like”按钮时,问题就出现了 - 整个 ListView 被重建,而不是只更新那个特定的“like”按钮,从而导致性能开销。

我想要实现的是仅更新数据(如状态)已更改的特定“点赞”按钮小部件,而不影响列表项的其余部分。

我尝试过使用各种状态管理技术,例如 Obx、GetBuilder,甚至尝试过 Provider,但似乎都没有提供仅更新目标小部件的解决方案。

有人可以指导我如何在关联数据发生变化时有效地更新 ListView 中的相关小部件吗?任何见解、代码片段或示例将不胜感激。

谢谢!

flutter get flutter-getx flutter-listview
1个回答
0
投票

如果我理解正确,您的小部件通过更改“MyController”获得新状态。

如果有一种方法可以完成您需要的操作,而无需不断地为 MyController 设置新状态,您可以将此代码放入有状态小部件中。然后你可以在那里做你的事情,当你完成并想要设置一个新状态时,更新你的控制器。然后整个ListView只重建一次。

Container(
  padding: const EdgeInsets.symmetric(vertical: 32),
  color: colors[random.nextInt(colors.length)],
  child: Row(
    children: [
      Obx(
        () {
          MyLogs.warning('UPDATED INDEX : $index');
          return MyIconButton(
            onTap: () {
              doLike(controller.listOfSelection ?? [], currentFile.value.fileId, index);
            },
            iconData: FontAwesomeIcons.solidHeart,
            color: isExist(controller.listOfSelection ?? [], currentFile.value.fileId, index)
                ? isLiked(controller.listOfSelection ?? [], currentFile.value.fileId)
                    ? AppColor.redDark
                    : AppColor.white
                : AppColor.white,
          );
        },
      ),
      Text(controller.listOfFiles[index].value.fileId),
    ],
  ),
);
© www.soinside.com 2019 - 2024. All rights reserved.