我正在尝试构建一个类似于tinder的系统,其中有一堆用户可以滑动的卡,并且接下来的几张卡总是预装的。
为此,我有一个Stack
小部件,它构建了一系列纸牌子小部件并为它们提供要加载的内容的ID:
class PostCardStack extends StatefulWidget {
const PostCardStack({Key key, this.postIds, this.onCardDismissed})
: super(key: key);
final List<String> postIds;
final Function onCardDismissed;
@override
_PostCardStackState createState() => _PostCardStackState();
}
class _PostCardStackState extends State<PostCardStack> {
ValueNotifier<double> _notifier = ValueNotifier<double>(0.0);
_buildCardStack() {
List<Widget> cards = [];
for (String postId in widget.postIds) {
int idx = widget.postIds.indexOf(postId);
if (postId == widget.postIds.first) {
cards.add(CustomDismissible(
resizeDuration: null,
dismissThresholds: {CustomDismissDirection.horizontal: 0.2},
notifier: _notifier,
key: Key(postId),
onDismissed: (direction) {
_notifier.value = 0.0;
widget.onCardDismissed(postId);
},
child: SlidablePanel(
panel: AnimatedBuilder(
animation: _notifier,
child: PostCard(
postId: postId,
),
builder: (context, _) {
return Opacity(
opacity: 1 - _notifier.value,
child: PostCard(
postId: postId,
));
}),
)));
} else {
cards.add(AnimatedBuilder(
animation: _notifier,
child: PostCard(
postId: postId,
),
builder: (context, _) {
return Opacity(
opacity: lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
child: Transform(
origin: null,
alignment: Alignment.bottomCenter,
transform: Matrix4.translationValues(
0.0,
lerpDouble(
-idx * 35, (-idx * 35 + 35), _notifier.value),
0.0)
..scale(
lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
1),
child: PostCard(
postId: postId,
)));
}));
}
}
return cards.reversed.toList();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter, children: _buildCardStack());
}
}
在PostCard
小部件中,我使用postId
参数来获取卡信息并在准备好信息时对其进行构建。
class PostCard extends StatefulWidget {
const PostCard({Key key, this.postId}) : super(key: key);
final String postId;
@override
_PostCardState createState() => _PostCardState();
}
class _PostCardState extends State<PostCard> {
PostModel post;
@override
void initState() {
super.initState();
print("${widget.postId} mounted");
_fetchPost(widget.postId);
}
@override
void dispose() {
print("${widget.postId} disposed");
super.dispose();
}
_fetchPost(String postId) async {
PostModel fullPost = await blablaFirestore(postId);
setState(() {
post = fullPost;
});
}
@override
Widget build(BuildContext context) {
return Container(
height: 300,
child: Align(
alignment: Alignment.topCenter,
child: Text(post == null ? "Loading..." : post.text),
),
);
}
}
一切正常,除了当Stack组件中id列表中的任何元素发生变化时,所有子卡都将重建,因此失去了它们先前加载的状态,不得不再次获取数据。
如果ID列表中只有一个元素发生变化,为什么每张卡都需要重建?我在这里想念什么吗? :)
编辑:在标记为重复的问题中,问题是构建方法具有副作用。我不认为这是事实。在我的情况下,问题在于即使使用完全相同的参数(postId)进行重建,PostCards小部件的状态也不会保留
干杯!
答案 0 :(得分:1)
再次调用protected override void OnDrawItem(DrawItemEventArgs e)
{
// (...)
e.DrawBackground();
using (var brush = new SolidBrush(this.ForeColor)) {
e.Graphics.DrawString(this.GetItemText(this.Items[e.Index]), this.Font, brush, e.Bounds);
}
// (...)
}
函数时,setState
函数将被重新创建,因为所有build
小部件都是在PostCard
函数中创建的。
这就是说,如果build
是PostCard
小部件,则状态不应被破坏(例如,不会在其上调用initState)。但是您可能会失去对它们的引用,这可能就是为什么您的代码无法按预期运行的原因(很难从您的代码中看出来)。
也许您应该制作此代码称为Stateful
小部件的小部件,并创建一个Stateful
变量来存储您的卡,这样您就可以在{ {1}}函数,并且当您调用List<PostCard> postCards
时不会重新创建它们,从而保留了引用。