Как я могу обновить список после изменения статуса предмета? (Флаттер и Провайдер) - PullRequest
0 голосов
/ 12 июля 2020

Всем привет и спасибо, что посмотрели на мой вопрос.

У меня проблема: у меня есть список элементов, каждый из которых имеет статус избранного, и у меня есть страница, на которой показаны избранные элементы. Я хочу, чтобы страница обновлялась и удаляла не избранные элементы, когда я переключаю статус избранного.

Попытка с ChangeNotifierProxyProvider также безуспешна, статус меняется, но notifyListeners не обновляет основной список. Я знаю трюк с enpty setState в середине приложения, чтобы вызвать refre sh, но я знаю, что есть более аккуратный метод с участием Provider, о котором я не знаю.

Еще раз спасибо!

Это код (я сделал его максимально коротким)

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Collection(),
      builder: (context, child) => MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final _list = Provider.of<Collection>(context).favItems;

    return Scaffold(
      appBar: AppBar(
        title: Text("Test"),
      ),
      body: Container(
        child: ListView.builder(
          itemCount: _list.length,
          itemBuilder: (_, index) => ChangeNotifierProvider.value(
            value: _list[index],
            child: CardWidget(),
          ),
        ),
      ),
    );
  }
}

class CardWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final _item = Provider.of<Items>(context);

    return Card(
      child: Row(
        children: <Widget>[
          Text(_item.name),
          IconButton(
              icon:
                  _item.favourite ? Icon(Icons.star) : Icon(Icons.star_border),
              onPressed: () {
                _item.toggleFavourite();
              })
        ],
      ),
    );
  }
}

class Collection with ChangeNotifier {
  List<Items> _items = [
    Items(name: "a", favourite: true),
    Items(name: "b", favourite: true),
    Items(name: "c", favourite: true),
  ];

  List<Items> get favItems =>
      [..._items].where((element) => element.favourite == true).toList();
}

class Items with ChangeNotifier {
  String name;
  bool favourite;

  Items({this.name, this.favourite});

  toggleFavourite() {
    favourite = !favourite;
    notifyListeners();
  }
}

Ответы [ 3 ]

0 голосов
/ 13 июля 2020

Попробуйте использовать метод setState (), который перестроит ваш экран, и вы увидите изменения

0 голосов
/ 13 июля 2020

Если честно, провайдер работает путем распространения данных вниз по дереву виджетов от родителя к потомкам, но вы хотите, чтобы потомок (Item) уведомил родителя об изменении (Collection), и это сделало бы и родитель, и дети созависимы (что позже приведет к некоторому коду спагетти). Если каждое изменение в избранном будет обновлять список, тогда было бы лучше просто сохранить весь logi c в Collection и оставить класс Item как простую модель

class Collection with ChangeNotifier {
  List<Items> _items = [
    Items(name: "a", favourite: true),
    Items(name: "b", favourite: true),
    Items(name: "c", favourite: true),
  ];

  List<Items> get favItems =>
      [..._items].where((element) => element.favourite == true).toList();

  toggleFavourite(Item item) {
    int index = _items.indexWhere((element) => element.name == item.name);
    _items[index].favourite = !_items[index].favourite;
    notifyListeners();
  }
}

class Items { //simple Model class
  String name;
  bool favourite;

  Items({this.name, this.favourite});
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final _list = context.select((Collection list) => list.favItems); 
    //to update only if list is different

    return Scaffold(
      appBar: AppBar(
        title: Text("Test"),
      ),
      body: Container(
        child: ListView.builder(
          itemCount: _list.length,
          itemBuilder: (_, index) => CardWidget(_list[index])
        ),
      ),
    );
  }
}

class CardWidget extends StatelessWidget {
  final Item _item;

  CardWidget(this._item);

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Row(
        children: <Widget>[
          Text(_item.name),
          IconButton(
              icon:
                  _item.favourite ? Icon(Icons.star) : Icon(Icons.star_border),
              onPressed: () {
                Provider.of<Collection>(context, listen: false).toggleFavourite(_item);
              })
        ],
      ),
    );
  }
}
0 голосов
/ 12 июля 2020

Проблема в том, что список не обновляется визуально, хотя элемент удален из списка? Попробуйте использовать:

Container(
    key: UniqueKey(),
    child: CardWidget()
)

Я не знаю, почему это работает, но у меня это сработало, когда у меня была эта проблема.

...