how to keep the state of my widgets after scrolling?

久未见 提交于 2020-05-13 04:55:45

问题


I'm codeing an app with flutter an i'm haveing problems with the development. I'm trying to have a listview with a custom widget that it has a favourite icon that represents that you have liked it product. I pass a boolean on the constructor to set a variables that controls if the icons is full or empty. When i click on it i change it state. It works awesome but when i scroll down and up again it loses the lastest state and returns to the initial state. Do you know how to keep it states after scrolling?

Ty a lot <3

Here is my code:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new ListView.builder(
        itemCount: 100,
        itemBuilder: (BuildContext context, int index){
          return new LikeClass(liked: false);
        },
      ),
    );
  }
}

class LikeClass extends StatefulWidget {
  final bool liked;//i want this variable controls how heart looks like

  LikeClass({this.liked});

  @override
  _LikeClassState createState() => new _LikeClassState();
}

class _LikeClassState extends State<LikeClass> {
  bool liked;
  @override
  void initState() {
    liked=widget.liked;
  }
  @override
  Widget build(BuildContext context) {
    return new Container(
      child: new Column(
        children: <Widget>[
          new GestureDetector(
            onTap:((){
              setState(() {
                liked=!liked;
                //widget.liked=!widget.liked;
              });
            }),
            child: new Icon(Icons.favorite, size: 24.0,
              color: liked?Colors.red:Colors.grey,
              //color: widget.liked?Colors.red:Colors.grey,//final method to control the appearance
            ),
          ),
        ],
      ),
    );
  }
}

回答1:


You have to store the state (favorite or not) in a parent widget. The ListView.builder widget creates and destroys items on demand, and the state is discarded when the item is destroyed. That means the list items should always be stateless widgets.

Here is an example with interactivity:

class Item {
  Item({this.name, this.isFavorite});

  String name;
  bool isFavorite;
}

class MyList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyListState();
}

class MyListState extends State<MyList> {
  List<Item> items;

  @override
  void initState() {
    super.initState();

    // Generate example items
    items = List<Item>();
    for (int i = 0; i < 100; i++) {
      items.add(Item(
        name: 'Item $i',
        isFavorite: false,
      ));
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ListItem(
          items[index],
          () => onFavoritePressed(index),
        );
      },
    );
  }

  onFavoritePressed(int index) {
    final item = items[index];
    setState(() {
      item.isFavorite = !item.isFavorite;
    });
  }
}

class ListItem extends StatelessWidget {
  ListItem(this.item, this.onFavoritePressed);

  final Item item;
  final VoidCallback onFavoritePressed;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(item.name),
      leading: IconButton(
        icon: Icon(item.isFavorite ? Icons.favorite : Icons.favorite_border),
        onPressed: onFavoritePressed,
      ),
    );
  }
}



回答2:


If you don't have many items in the ListView you can replace it with a SingleChildScrollview and a Column so that the Widgets aren't recycled. But it sounds like you should have a list of items where each item has an isFavourite property, and control the icon based on that property. Don't forget to setState when toggling the favorite.




回答3:


A problem with what you are doing is that when you change the liked variable, it exists in the Widget state and nowhere else. ListView items share Widgets so that only a little more than are visible at one time are created no matter how many actual items are in the data.

For a solution, keep a list of items as part of your home page's state that you can populate and refresh with real data. Then each of your LikedClass instances holds a reference to one of the actual list items and manipulates its data. Doing it this way only redraws only the LikedClass when it is tapped instead of the whole ListView.

class MyData {
  bool liked = false;
}

class _MyHomePageState extends State<MyHomePage> {
  List<MyData> list;
  _MyHomePageState() {
    // TODO use real data.
    list = List<MyData>();
    for (var i = 0; i < 100; i++) list.add(MyData());
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new ListView.builder(
        itemCount: list.length,
        itemBuilder: (BuildContext context, int index) {
          return new LikeClass(list[index]);
        },
      ),
    );
  }
}

class LikeClass extends StatefulWidget {
  final MyData data;

  LikeClass(this.data);

  @override
  _LikeClassState createState() => new _LikeClassState();
}

class _LikeClassState extends State<LikeClass> {
  @override
  Widget build(BuildContext context) {
    return new Container(
      child: new Column(
        children: <Widget>[
          new GestureDetector(
            onTap: (() {
              setState(() {
                widget.data.liked = !widget.data.liked;
              });
            }),
            child: new Icon(
              Icons.favorite,
              size: 24.0,
              color: widget.data.liked ? Colors.red : Colors.grey,
            ),
          ),
        ],
      ),
    );
  }
}


来源:https://stackoverflow.com/questions/51071906/how-to-keep-the-state-of-my-widgets-after-scrolling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!