Flutter:子有状态小部件的维护状态
Flutter: Maintant state of child stateful widget
我在有状态小部件中有一个 listview.builder,我为项目 (ImageCard) 创建了一个单独的有状态小部件。
在 ImageCard 小部件中,当我单击它时,我有一个喜欢按钮,它的颜色变为红色(喜欢)、灰色(不喜欢)。
问题是,当我向下滚动并 return 返回时,颜色始终为灰色,这意味着没有保存任何状态!
如何通知父有状态小部件保持状态?
父有状态小部件
@override
Widget build(BuildContext context) {
return _buildListView(models, _scrollController);
}
Widget _buildListView(
List<PhotoModel> models, ScrollController scrollController) {
return Container(
child: ListView.builder(
controller: scrollController,
itemCount: models.length,
itemBuilder: (context, int index) {
if (index == models.length - 1) {
return SpinKitThreeBounce(
color: Colors.purple,
size: 30.0,
);
} else {
return ImageCard(
models[index].regularPhotoUrl,
models[index].mediumProfilePhotoUrl,
models[index].name,
models[index].color);
}
}));
}
子状态小部件
class ImageCard extends StatefulWidget {
final String imageUrl, userProfilePic, userName, color;
ImageCard(this.imageUrl, this.userProfilePic, this.userName, this.color);
@override
_ImageCardState createState() => _ImageCardState();
}
class _ImageCardState extends State<ImageCard> {
bool isLiked = false, isFollowing = false;
@override
Widget build(BuildContext context) {
return new Card( ....
void _onLikedBtnClicked() {
setState(() {
if (isLiked)
isLiked = false;
else {
isLiked = true;
}
});
}
那你应该单独保存你的状态。您可以制作一个 List<bool>
并在其中为每个列表项设置一个值。无论如何,您可能想在某个时候保存或使用数据,那么此机制将无用。
Flutter 会自动处理移出屏幕的 widget,当它们重新出现时,将重新构建而不是恢复。
所以通常的做法是将状态保存在高级小部件中,它至少包含业务逻辑的完整方面并且不会很快被处理掉。然后状态的变化被映射到子部件中。
对于您的具体情况,一个简单的解决方案是:将信息存储在父窗口小部件中,并将它们映射到父窗口小部件的构建函数中的 ImageCard。
添加isliked
,isfollowing
属性到模型,然后
class SomeParentState extends State<SomeParent> {
List<Model> models;
//.......
@override
Widget build(BuildContext context) {
return _buildListView(models, _scrollController);
}
Widget _buildListView(List<PhotoModel> models,
ScrollController scrollController) {
return Container(
child: ListView.builder(
controller: scrollController,
itemCount: models.length,
itemBuilder: (context, int index) {
if (index == models.length - 1) {
return SpinKitThreeBounce(
color: Colors.purple,
size: 30.0,
);
} else {
return ImageCard(
models[index].regularPhotoUrl,
models[index].mediumProfilePhotoUrl,
models[index].name,
models[index].color,
models[index].isLiked,
models[index].isFollowing,
() {
setState(() {
models[index].isLiked = !models[index].isLiked;
});
},
() {
setState(() {
models[index].isFollowing = !models[index].isFollowing;
});
},
);
}
}));
}
}
class ImageCard extends StatelessWidget{
ImageCard(
//...,
this.isLiked,
this.isFollowing,
this.likeBtnClickedListener,
this.followBtnClickedListener,
)
//...
Widget build(BuildContext context){
return Card(
//.......
IconButton(
onPressed: likeBtnClickedListener,
),
IconButton(
onPressed: followBtnClickedListener,
),
)
}
}
这应该基本解决了你的问题。无论如何,通过这种方法访问和同步子控件中的数据更容易。
如果您发现让子部件保持活动状态更容易,您可以阅读 AutomaticKeepAliveClientMixin 的文档。当它移出视线时,它将阻止 flutter 杀死这个小部件。但是有内存泄漏的风险。
要在 ListView
中维护小部件的状态,您需要 AutomaticKeepAlive or AutomaticKeepAliveMixin(对于自定义小部件)
这将确保 State
实例在离开屏幕时不会被销毁
ListView(
children: [
// Not kept alive
Text('Hello World'),
// kept alive
AutomaticKeepAlive(
child: Text("Hello World"),
),
]
),
我在有状态小部件中有一个 listview.builder,我为项目 (ImageCard) 创建了一个单独的有状态小部件。 在 ImageCard 小部件中,当我单击它时,我有一个喜欢按钮,它的颜色变为红色(喜欢)、灰色(不喜欢)。 问题是,当我向下滚动并 return 返回时,颜色始终为灰色,这意味着没有保存任何状态! 如何通知父有状态小部件保持状态?
父有状态小部件
@override
Widget build(BuildContext context) {
return _buildListView(models, _scrollController);
}
Widget _buildListView(
List<PhotoModel> models, ScrollController scrollController) {
return Container(
child: ListView.builder(
controller: scrollController,
itemCount: models.length,
itemBuilder: (context, int index) {
if (index == models.length - 1) {
return SpinKitThreeBounce(
color: Colors.purple,
size: 30.0,
);
} else {
return ImageCard(
models[index].regularPhotoUrl,
models[index].mediumProfilePhotoUrl,
models[index].name,
models[index].color);
}
}));
}
子状态小部件
class ImageCard extends StatefulWidget {
final String imageUrl, userProfilePic, userName, color;
ImageCard(this.imageUrl, this.userProfilePic, this.userName, this.color);
@override
_ImageCardState createState() => _ImageCardState();
}
class _ImageCardState extends State<ImageCard> {
bool isLiked = false, isFollowing = false;
@override
Widget build(BuildContext context) {
return new Card( ....
void _onLikedBtnClicked() {
setState(() {
if (isLiked)
isLiked = false;
else {
isLiked = true;
}
});
}
那你应该单独保存你的状态。您可以制作一个 List<bool>
并在其中为每个列表项设置一个值。无论如何,您可能想在某个时候保存或使用数据,那么此机制将无用。
Flutter 会自动处理移出屏幕的 widget,当它们重新出现时,将重新构建而不是恢复。
所以通常的做法是将状态保存在高级小部件中,它至少包含业务逻辑的完整方面并且不会很快被处理掉。然后状态的变化被映射到子部件中。
对于您的具体情况,一个简单的解决方案是:将信息存储在父窗口小部件中,并将它们映射到父窗口小部件的构建函数中的 ImageCard。
添加isliked
,isfollowing
属性到模型,然后
class SomeParentState extends State<SomeParent> {
List<Model> models;
//.......
@override
Widget build(BuildContext context) {
return _buildListView(models, _scrollController);
}
Widget _buildListView(List<PhotoModel> models,
ScrollController scrollController) {
return Container(
child: ListView.builder(
controller: scrollController,
itemCount: models.length,
itemBuilder: (context, int index) {
if (index == models.length - 1) {
return SpinKitThreeBounce(
color: Colors.purple,
size: 30.0,
);
} else {
return ImageCard(
models[index].regularPhotoUrl,
models[index].mediumProfilePhotoUrl,
models[index].name,
models[index].color,
models[index].isLiked,
models[index].isFollowing,
() {
setState(() {
models[index].isLiked = !models[index].isLiked;
});
},
() {
setState(() {
models[index].isFollowing = !models[index].isFollowing;
});
},
);
}
}));
}
}
class ImageCard extends StatelessWidget{
ImageCard(
//...,
this.isLiked,
this.isFollowing,
this.likeBtnClickedListener,
this.followBtnClickedListener,
)
//...
Widget build(BuildContext context){
return Card(
//.......
IconButton(
onPressed: likeBtnClickedListener,
),
IconButton(
onPressed: followBtnClickedListener,
),
)
}
}
这应该基本解决了你的问题。无论如何,通过这种方法访问和同步子控件中的数据更容易。
如果您发现让子部件保持活动状态更容易,您可以阅读 AutomaticKeepAliveClientMixin 的文档。当它移出视线时,它将阻止 flutter 杀死这个小部件。但是有内存泄漏的风险。
要在 ListView
中维护小部件的状态,您需要 AutomaticKeepAlive or AutomaticKeepAliveMixin(对于自定义小部件)
这将确保 State
实例在离开屏幕时不会被销毁
ListView(
children: [
// Not kept alive
Text('Hello World'),
// kept alive
AutomaticKeepAlive(
child: Text("Hello World"),
),
]
),