为啥 AnimatedList 在颤动中不使用 bloc 状态的列表构建?

Posted

技术标签:

【中文标题】为啥 AnimatedList 在颤动中不使用 bloc 状态的列表构建?【英文标题】:Why is AnimatedList not building using list from bloc state in flutter?为什么 AnimatedList 在颤动中不使用 bloc 状态的列表构建? 【发布时间】:2021-10-01 20:08:52 【问题描述】:

我正在尝试使用bloc 模式创建AnimatedList,但遇到了一些问题。

当我将 AnimatedList 的 initialItemsCount 设置为 state.itemList.length 时,它不会构建。虽然当我在BlocConsumer 的监听器中打印出state.itemList(来自ListBloc)时,它会打印出itemList

那么,问题是为什么这不起作用?

我尝试对ListView.builder 做同样的事情,它工作正常。我是否遗漏了什么,或者 AnimatedList 甚至不应该使用 bloc 工作?

这里有一些示例代码,在这种情况下非常简单:

MyApp 类:

class _MyAppState extends State<MyApp> 
  final key = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) 
    return BlocProvider(
      create: (context) => ListBloc()..add(LoadList()),
      child: MaterialApp(
        home: SafeArea(
          child: BlocConsumer<ListBloc, ListState>(
            listener: (_, state) 
              print(state.itemList);
            ,
            builder: (context, state) => Scaffold(
              body: Column(
                children: [
                  Expanded(
                    child: AnimatedList(
                      key: key,
                      initialItemCount: state.itemList.length,
                      itemBuilder: (context, index, animation) 
                        return Item(
                            animation: animation,
                            index: index,
                            text: state.itemList[index],
                            onTap: () => removeItem(index, state.itemList));
                      ,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  

  void removeItem(int index, List<String> items) 
    final item = items.removeAt(index);

    key.currentState?.removeItem(
        index,
        (context, animation) => Item(
            animation: animation,
            index: index,
            text: items[index],
            onTap: () => removeItem(index, items)));
  

物品类别:

class Item extends StatelessWidget 
  final Animation<double> animation;
  final int index;
  final String text;
  final VoidCallback onTap;

  const Item(
      required this.animation,
      required this.index,
      required this.text,
      required this.onTap,
      Key? key)
      : super(key: key);

  @override
  Widget build(BuildContext context) 
    return ScaleTransition(
      scale: animation,
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: InkWell(
            onTap: onTap,
            child: Container(
              color: Colors.blue,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(text),
              ),
            )),
      ),
    );
  

集团:

class ListEvent extends Equatable 
  const ListEvent();

  @override
  List<Object> get props => [];


class LoadList extends ListEvent 

class ListState extends Equatable 
  final List<String> itemList;

  const ListState(required this.itemList);

  @override
  List<Object> get props => [itemList];


class ListBloc extends Bloc<ListEvent, ListState> 
  ListBloc() : super(ListState(itemList: []));

  @override
  Stream<ListState> mapEventToState(ListEvent event) async* 
    if (event is LoadList) 
      var items = ['1', '2', '3', '4', '5', '6'];
      yield ListState(itemList: items);
    
  

谢谢!

【问题讨论】:

【参考方案1】:

我在 AnimatedList 中遇到过类似的场景,即 itemBuilder 的调用方式和列表的重建方式。

如果您在 AnimatedList 小部件(即您的父 Expanded 小部件)上方和 itemBuilder 调用中设置断点,您可能会注意到在某些情况下 itemBuilder 正在执行而第一个断点未命中.

这看起来是因为 AnimatedList 的动画特性导致 itemBuilder 被直接调用为框架页面刷新的一部分(在包含的小部件之外,例如您的 BlocConsumer,因此您的状态尚未按预期设置)。

【讨论】:

以上是关于为啥 AnimatedList 在颤动中不使用 bloc 状态的列表构建?的主要内容,如果未能解决你的问题,请参考以下文章

可扩展的浮动操作按钮(使用堆栈)在颤动中不起作用

iCheck 复选框在颤动的 Android 网络视图中不起作用

方向性(textDirection:TextDirection.rtl,)在颤动中不起作用

为啥小部件的状态在颤动时没有改变?

在 StreamBuilder 中使用 AnimatedList

在 Flutter 中使用 Provider 更新和动画化 AnimatedList