【问题标题】:Flutter: Maintant state of child stateful widgetFlutter:子状态小部件的维护状态
【发布时间】:2019-04-26 02:08:36
【问题描述】:

我在有状态小部件中有一个 listview.builder,并且我为该项目 (ImageCard) 创建了一个单独的有状态小部件。 在 ImageCard 小部件中,当我单击它时,我有一个喜欢按钮,它的颜色变为红色(喜欢),灰色(不喜欢)。 问题是当我向下滚动并返回时,颜色始终为灰色,这意味着没有保存任何状态! 如何通知父有状态小部件保持状态?

父状态小部件

@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;
      }
    });
  }

【问题讨论】:

  • 那么您在 ImageCard 中的哪个位置保存了 isLiked 属性?它是指color 属性吗?
  • 它显示在我的代码中,我将它保存在状态类中
  • 如果 isLiked 为真,我将 btn 的颜色设置为红色

标签: dart flutter flutter-layout


【解决方案1】:

Flutter 会自动处理移出屏幕的小部件,当它们重新出现时,它们将被重新构建而不是恢复。

因此常见的做法是将状态保存在高级小部件中,该小部件至少包含业务逻辑的完整方面,并且不会很快被释放。然后将状态的变化映射到子小部件中。

对于您的具体情况,一个简单的解决方案是:您将信息存储在父窗口小部件中,并将它们映射到父窗口小部件的构建函数内的 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 的文档。当它移出视线时,它将阻止颤动杀死这个小部件。但是有造成内存泄露的风险。

【讨论】:

  • 你是对的!我发现 ListView.builder 小部件按需创建和销毁项目,并且在项目被销毁时丢弃状态。因此必须使 ImageCard 成为无状态小部件
【解决方案2】:

要在ListView 中维护小部件的状态,您需要AutomaticKeepAliveAutomaticKeepAliveMixin(用于自定义小部件)

这将确保State 实例在离开屏幕时不会被破坏

ListView(
  children: [
    // Not kept alive
    Text('Hello World'),
    // kept alive
    AutomaticKeepAlive(
     child: Text("Hello World"),
    ),
  ]
),

【讨论】:

  • 感谢您的提示,但@First_Strike 解决方案正是我所寻找的
【解决方案3】:

那么你应该单独保存你的状态。您可以创建一个List&lt;bool&gt; 并在其中为每个列表项设置一个值。无论如何,您可能希望在某个时候保存或使用数据,那么这种机制将毫无用处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-23
    • 2018-09-01
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    • 2021-06-27
    • 2021-02-16
    相关资源
    最近更新 更多