Как заставить ListView.builder обновить sh при добавлении / удалении элементов в Flutter? - PullRequest
1 голос
/ 04 февраля 2020

Я знаю, что могу использовать this.setState() на родительском экране Stateful Widget, содержащем ListView.builder, чтобы ListView перестроил свой список.

Проблема в том, что я использую другой дочерний виджет с состоянием для создания каждого из элемент ListView. В документации Flutter сказано, что сборка дерева останавливается всякий раз, когда он встречает один и тот же виджет. Это приводит к тому, что содержимое ListView не перестраивается.

Как я могу заставить ListView «аннулировать» все его дочерние элементы и принудительно перестроить весь контент без указания таких вещей, как ключи (глобальные ключи / локальные ключи)?

РЕДАКТИРОВАТЬ: упрощенный код.

class PostList extends extends StatefulWidget {
    final UserModel user;
    PostList({ this.user }): super();
    @override
      _PostListState createState() => _PostListState();
}

class _PostListState extends State<PostList> {
    UserModel _user;
    List<PostModel> _posts;
    final _repository = Repository();

    @override
    void initState() {
      _user = widget.user;
      _repository.fetchPosts(userId: user.id)
        .then((response) => this.setState(() => _posts = response)
        .catchError((onError) => debugPrint(onError);
    }

    addNewRandomPost() {
      final newPost = PostModel(text: DateTime.now().millisecondsSinceEpoch.toString());
      this.setState(() => _posts = [newPost]..addAll(_posts ?? []));
    }


    @override
    Widget build(BuildContext context) {
      return Scaffold(appBar: AppBar(title: "Post list"),
        body: ListView.builder(
          itemCount: (_posts?.length ?? 0) + 1,
          itemBuilder: (context, index) {
            if (index == 0) 
              return RaisedButton(child: Text("Add new random post"), onPressed: addNewRandomPost);
            else if(_posts == null) 
              return Center(child: CircularProgressIndicator());
            else 
              return PostCard(post: _posts[index - 1]);
          }
        )
    }
}

class PostCard extends StatefulWidget {
  final PostModel post;
  PostCard ({ this.post }): super();
  @override
  _PostCardState createState() => _PostCardState();
}

class _PostCardState extends State<PostCard> {
  PostModel _post;
  @override
  void initState() {
    _post = widget.post;
  }

  @override
  Widget build(BuildContext context) => Card(child: 
    Padding(padding: EdgeInsets.all(10), child: Text(_post.text));
}

Очевидно, что для виджета PostCard есть больше кода и цели, которые я намеренно сделал его виджетом с сохранением состояния, а не без сохранения состояния. Но я просто упростил это здесь, чтобы показать, что даже с этим простым кодом, при каждом нажатии «Добавить новый случайный пост»:

  • , когда изначально нет поста, список превращается из простого отображения круглого индикатора в правильно отображать новое сообщение.
  • , но если там уже есть новое сообщение (_posts не равно нулю), если я добавляю новое сообщение в начале списка, существующая открытка, которая уже создана, не меняется Он добавляет только новый виджет почтовой открытки внизу списка, показывающий последнее сообщение в списке, которое по иронии судьбы было первыми данными, которые передаются последним. Таким образом, на всех почтовых карточках отображаются одни и те же данные, хотя содержание сообщений фактически отличается одно от другого.

Что я ожидаю после пяти нажатий кнопки:

[ Add new random post ]
1580789378
1580789373
1580789363
1580789349
1580789332

Что я получу:

[ Add new random post ]
1580789332
1580789332
1580789332
1580789332
1580789332

1 Ответ

0 голосов
/ 04 февраля 2020

Вы можете сделать это следующим образом

List your_data_container;
_yourDeleteMethod()async{
  *your way of deleting*
  if(response.statuscode == 200){
    _fetchListContent();
  }
}
_yourUpdateMethod()async{
  *your way of Updating*
  if(response.statuscode == 200){
    _fetchListContent();
  }
}
_fetchListContent()async{
  *your way of fetching*
  if(response.statuscode==200){
    fetched_data = json.decode(response.body);
    setState((){
      your_data_container = *fetched_data*;
    })
  }
}
ListView.builder(
  itemCount: your_data_container.length,
  itemBuilder: (context, index){
  return Container(
    width: screenWidth,
    height: screenHeight/15,
    child: Row(
      children: <Widget>[
        Expanded(
          child: Text(index.toString)
        ),
        IconButton(
          icon: Icon(Icons.delete, color: Colors.red)
          onPressed: (){
            _yourDeleteMethod();

          }
        ),
        IconButton(`
          icon: Icon(Icons.edit)
          onPressed: (){
            _yourUpdateMethod();
          }
        )
      ]
    )
  );
}
)

ПРИМЕЧАНИЕ: ListView.builder должен быть внутри сборки или как виджет, это просто для того, чтобы дать вам представление, что это не весь код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...