强制堆栈重新创建自定义小部件
Force Stack to recreate custom widget
我有两个自定义小部件的堆栈,它们都已定位:
- 资料卡
- ProfileCardDummy
ProfileCard:这个自定义Stateful Widget是第一个stack的widget,stack在最上面。此小部件已被拒绝。
ProfileCardDummy:这个自定义无状态小部件是堆栈的背景小部件。
所以 ProfileCard 小部件是 Stack 顶部的小部件,其他背景堆栈是 ProfileCardDummy
我的代码是这样的:
return Stack(
alignment: AlignmentDirectional.center,
children:
state.profileCards.map((ProfileCardModel card) {
backCardWidth += 10.0;
backBottom -= decrementalBottom;
if (state.profileCards.indexOf(card) ==
state.profileCards.length - 1) {
return BlocProvider < ProfileCardBloc > (
bloc: _profileCardBloc,
child: ProfileCard(
isBack: 0,
bottom: initialBottom,
cardModel: card,
rotation: 0.0,
skew: 0.0,
img: image1,
addCard: () {},
onPressed: () {},
),
);
} else {
return ProfileCardDummy(
card,
image2,
backBottom,
backCardWidth,
);
}
}).toList()
);
所有魔法都发生在 ProfileCard 中,我在其中使用 BloC 模式获取卡片内容(主要是按钮)。
我正在 ProfileCard 状态的构造函数上调度 bloc 事件。类似于:
class _ProfileCardState extends State<ProfileCard> {
final VoteButtonBloc _voteButtonBloc = VoteButtonBloc();
_ProfileCardState(){
print("Dispatching ${widget.cardModel}");
_voteButtonBloc.dispatch(FetchButtons(widget.cardModel));
}
...
...
问题是,当我 运行 代码时,第一个 ProfileCard 正确显示其按钮。现在,当我关闭它时,会显示第二个 ProfileCard,但会显示第一个 ProfileCard(我关闭的那个)的按钮。
经过几个小时的调试,我注意到 ProfileCard 的构造函数 (_ProfileCardState()) 仅在第一张卡片上被调用。其他卡片继承第一个class的按钮。
在 Stack 的文档中,它说:
If you reorder the children in this way, consider giving the children non-null keys.
These keys will cause the framework to move the underlying objects for the children to their new locations rather than recreate them at their new location.
我的 ProfileCard 将密钥作为参数(因为它扩展了 StatefulWidget),但我没有传递任何密钥。传递密钥可以解决这个问题吗?如何传递唯一键?:P
有没有一种方法可以强制重新创建小部件以强制再次调用构造函数,从而正确获取按钮?
要事第一。当您在列表中有相同的小部件时,Flutter 不会知道它们是否更改了顺序,这就是 key
可以帮助您的地方。
要查看如何使用键,您可能需要查看 and this video,它很好地解释了例如您想要重新订购项目的列表场景。
A setState
将调用树中已经存在的小部件状态中的 build
,但不会调用构造函数或 initState
,这些仅在小部件处于实际上插入树中。当父级发生变化时,Flutter 将查找其子级的变化,并在每个小部件状态上调用 didUpdateWidget
方法,您可以覆盖并实际比较旧小部件与新小部件的变化。
既然你总是想重建小部件,就这样给它一个UniqueKey
ProfileCard(key: UniqueKey());
这将告诉 Flutter 您实际上是在创建一个新对象,而不是重新使用旧对象。
我有两个自定义小部件的堆栈,它们都已定位:
- 资料卡
- ProfileCardDummy
ProfileCard:这个自定义Stateful Widget是第一个stack的widget,stack在最上面。此小部件已被拒绝。
ProfileCardDummy:这个自定义无状态小部件是堆栈的背景小部件。
所以 ProfileCard 小部件是 Stack 顶部的小部件,其他背景堆栈是 ProfileCardDummy
我的代码是这样的:
return Stack(
alignment: AlignmentDirectional.center,
children:
state.profileCards.map((ProfileCardModel card) {
backCardWidth += 10.0;
backBottom -= decrementalBottom;
if (state.profileCards.indexOf(card) ==
state.profileCards.length - 1) {
return BlocProvider < ProfileCardBloc > (
bloc: _profileCardBloc,
child: ProfileCard(
isBack: 0,
bottom: initialBottom,
cardModel: card,
rotation: 0.0,
skew: 0.0,
img: image1,
addCard: () {},
onPressed: () {},
),
);
} else {
return ProfileCardDummy(
card,
image2,
backBottom,
backCardWidth,
);
}
}).toList()
);
所有魔法都发生在 ProfileCard 中,我在其中使用 BloC 模式获取卡片内容(主要是按钮)。
我正在 ProfileCard 状态的构造函数上调度 bloc 事件。类似于:
class _ProfileCardState extends State<ProfileCard> {
final VoteButtonBloc _voteButtonBloc = VoteButtonBloc();
_ProfileCardState(){
print("Dispatching ${widget.cardModel}");
_voteButtonBloc.dispatch(FetchButtons(widget.cardModel));
}
...
...
问题是,当我 运行 代码时,第一个 ProfileCard 正确显示其按钮。现在,当我关闭它时,会显示第二个 ProfileCard,但会显示第一个 ProfileCard(我关闭的那个)的按钮。
经过几个小时的调试,我注意到 ProfileCard 的构造函数 (_ProfileCardState()) 仅在第一张卡片上被调用。其他卡片继承第一个class的按钮。
在 Stack 的文档中,它说:
If you reorder the children in this way, consider giving the children non-null keys.
These keys will cause the framework to move the underlying objects for the children to their new locations rather than recreate them at their new location.
我的 ProfileCard 将密钥作为参数(因为它扩展了 StatefulWidget),但我没有传递任何密钥。传递密钥可以解决这个问题吗?如何传递唯一键?:P
有没有一种方法可以强制重新创建小部件以强制再次调用构造函数,从而正确获取按钮?
要事第一。当您在列表中有相同的小部件时,Flutter 不会知道它们是否更改了顺序,这就是 key
可以帮助您的地方。
要查看如何使用键,您可能需要查看
A setState
将调用树中已经存在的小部件状态中的 build
,但不会调用构造函数或 initState
,这些仅在小部件处于实际上插入树中。当父级发生变化时,Flutter 将查找其子级的变化,并在每个小部件状态上调用 didUpdateWidget
方法,您可以覆盖并实际比较旧小部件与新小部件的变化。
既然你总是想重建小部件,就这样给它一个UniqueKey
ProfileCard(key: UniqueKey());
这将告诉 Flutter 您实际上是在创建一个新对象,而不是重新使用旧对象。