我正在尝试使用bloc
模式创建AnimatedList
,但遇到了一些问题。
当我将AnimatedList
的initialItemsCount设置为state.itemList.length
时,它不构建。虽然当我在BlocConsumer
的监听器中打印出state.itemList
(来自ListBloc
)时,它打印出itemList
。
那么,问题是为什么这不起作用?
我试图用ListView.builder
做同样的事情,它工作得很好。我错过了什么或AnimatedList
甚至不应该使用集团工作?
下面是一些示例代码,使其在这种情况下非常简单:
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);
}
}
}
谢谢!
我经历过类似的场景,关于AnimatedList的itemBuilder是如何被调用的,列表是如何重建的。
如果你在AnimatedList小部件(即你的父扩展小部件)和itemBuilder调用中设置了一个断点,你可能会注意到itemBuilder在某些情况下没有击中第一个断点就被执行。
这看起来是因为AnimatedList的动画特性导致itemBuilder作为框架页面刷新的一部分被直接调用(在包含的小部件之外,比如你的BlocConsumer,所以你的状态还没有像你期望的那样设置)。