flutter ListView.Builder不触发新的生成和更新小部件

s5a0g9ez  于 2023-06-07  发布在  Flutter
关注(0)|答案(1)|浏览(216)

我有一个非常简单的系统。它基本上由某个屏幕的主视图模型组成,该模型创建了注入到一些子部件上的子视图模型。
该主视图模型具有以下相关属性:

List<ChildrenViewModel> childrenViewModels;

int numberOfChildren() { return childrenViewModels.length; }

ChildrenViewModel childAt(int index) { return childrenViewModel[index]; }

void selectIfPossible(ChildrenViewModel child) { 
  //Business Logic to check if it is possible to select
  child.aCertainProperty.anotherProperty.selected = true;
  notifyObservers();
}

我的主Widget确实有一个List.builder,它看起来像:

ListView.builder(
  physics: const NeverScrollableScrollPhysics(),
  shrinkWrap: true,
  itemCount: numberOfChildren(),
  itemBuilder: (context, index) {
          return ChildWidget(
                  viewModel: viewModel.childAt(index));
            })
}

现在我的ChildWidget如下:

Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        viewModel.selectItem();
      },
      child: Column(
        children: [
          // a few widgets
          Image(
                    image: AssetImage(child.aCertainProperty.anotherProperty.selected
                        ? selectedImage
                        : unselectedImage)),
              ),
          // a few widgets
            ],
          ),
    );

在我的ChildViewModel上,onTap只执行以下操作:

void selectItem() {
    parentViewModel.selectIfPossible(this); //parentViewModel is the Main View Model on top
}

原理很简单。用户点击列表上的某个项目,在主视图模型上检查一些业务逻辑,然后通知观察者项目已更新,列表相应地更新项目。
然而,这根本不起作用。通过逐步调试,我可以看到视图模型中的数据是正确的,但是ListView.Builder永远不会返回更新的小部件。不知何故,在使用断点时,我可以一步一步地进行,直到itemCount: numberOfChildren(),但它永远不会前进到构建器本身,以便它可以返回更新的小部件。有没有人有任何提示,我做错了什么,我可以。改变来解决我的问题
先谢谢你了!
我已经尝试了我能想到的一切。它“工作”的唯一方法是,如果我把观察者放在Widget上,它是拥有ListView的Widget的父级,并强制构建ListView的整个树。然而,这样做的列表确实滚动回到顶部,这是可怕的用户体验。

pqwbnv8z

pqwbnv8z1#

如果我理解你的应用程序的权利,你只更新这个选择:

Image(
                    image: AssetImage(child.aCertainProperty.anotherProperty.selected
                        ? selectedImage
                        : unselectedImage)),
              )

如果是这样,试着找到一个关键,你可以提供给它。就像我评论中的链接。您必须提供唯一的密钥。但也是小部件持有的形象必须是有状态的!!!.
如果你想重新构建整个Listview,你必须检查Widget的变化,它正在构建ListView. builder。然后给予每个Item一个唯一的key,如下所示:

...
 return ChildWidget(
                  key: const ValueKey('$index_changeInfo'),
                  viewModel: viewModel.childAt(index));
/// change info should be always different! Since the Value key
///informs it children wheter to change or not, it should change. if
///you have index as the key, it never changes, so the children will
///never notice they have to rebuild.
            })
...

但这里的小部件是建设Listview必须是一个statefull!

相关问题