ListView.builder itemCount在StreamBuilder中未更新

时间:2019-08-27 05:55:40

标签: flutter dart google-cloud-firestore

我有一个Flutter应用程序,其中使用ListView.Builder生成列表,其中itemCount是Firestore集合中的文档数。

当我向集合中添加文档时,可以看到通过打印将其值更改为snapshot.data.documents.length,但itemCount并未更改,从而导致以下错误:

无效值:不在0..17范围内(包括18)

这是我针对同一问题创建的GitHub线程:https://github.com/flutter/flutter/issues/39206

这是有问题的页面的代码,我从中得到错误的列表是StreamBuilder中靠近底部的列表:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:cloud_firestore/cloud_firestore.dart';

/*
Visar kontaktinformation
 */

class Contact extends StatefulWidget {
  @override
  _ContactState createState() => _ContactState();
}

class _ContactState extends State<Contact> {
  _hasDesc(desc) {
    if (desc == '') {
      return false;
    } else {
      return true;
    }
  }
  String sortby = 'namn';
  bool decending = false;

  var showInfo;
  TextEditingController controller = new TextEditingController();
  String filter;

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      setState(() {
        filter = controller.text.toLowerCase(); //Gör om till gemener för att inte vara skiftlägeskänslig
      });
    });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  Widget _personer(context, DocumentSnapshot document, index) {
    //Skapar lista från databasen med kontaktinformation
    //Denna lista måste vara i rätt ordning i databasen
    final info = List<String>.from(document['info']);

    //Om sökrutan är tom visas alla personer, om inte så visas bara de som matchar filtret
    if (filter == null ||
        filter == '' ||
        document['namn'].toLowerCase().contains(filter) ||
        document['beskrivning'].toLowerCase().contains(filter)) {
      return Column(
        children: <Widget>[
          ListTile(
            onTap: () {
              setState(() {
                for (int i = 0; i < showInfo.length; i++) {
                  if (i != index) {
                    showInfo[i] = false; // för att enbart ett kort ska vara expanderat åt gången
                  }
                }
                showInfo[index] = !showInfo[index];
              });
            },
            title: Padding(
              padding: const EdgeInsets.fromLTRB(0, 4, 0, 4),
              child: Column(
                children: <Widget>[
                  Text(
                    document['namn'],
                    textAlign: TextAlign.center,
                    style: Theme.of(context).textTheme.headline,
                  ),
                  Visibility(
                    visible: _hasDesc(document['beskrivning']),
                    child: Text(
                      document['beskrivning'],
                      textAlign: TextAlign.center,
                      style: Theme.of(context).textTheme.subtitle.copyWith(fontSize: 20),
                    ),
                  ),
                  Visibility(
                    visible: showInfo[index],
                    child: ListView.builder(
                      //Bygger lista med kontaktinfo för varje person
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: info.length,
                      itemBuilder: (context, index) {
                        return Padding(
                          padding: const EdgeInsets.only(top: 5),
                          child: ButtonTheme(
                            child: GestureDetector(
                              onTap: () {
                                Clipboard.setData(ClipboardData(text: info[index]));
                                //skapar snackbar
                                final copiedTextSnackBar = SnackBar(
                                  content: Text('"${info[index].replaceAll('/', '')}" har kopierats'),
                                  action: SnackBarAction(
                                    label: 'Okej',
                                    onPressed: () => Scaffold.of(context).hideCurrentSnackBar(),
                                  ),
                                );
                                //Stänger eventuell snackbar och viar en ny
                                Scaffold.of(context).hideCurrentSnackBar();
                                Scaffold.of(context).showSnackBar(copiedTextSnackBar);
                              },
                              child: Text(
                                info[index].replaceAll('/', '\n'),
                                textAlign: TextAlign.center,
                                style: Theme.of(context).textTheme.body1.copyWith(
                                  fontSize: 16,
                                  color: Color(0xff555555),
                                ),
                              ),
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          ),
          Divider(
            color: Colors.black,
          ),
        ],
      );
    } else {
      return SizedBox(
        height: 0, //Visar ingenting om filtret inte stämmer
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              Flexible(
                child: TextField(
                  decoration: InputDecoration(
                    contentPadding: EdgeInsets.fromLTRB(20, 10, 20, 10),
                    hintText: 'Sök',
                    border: InputBorder.none,
                  ),
                  controller: controller,
                ),
              ),
              Text('Sortera:   ', style: TextStyle(fontSize: 16, color: Color(0xff555555)),),
              DropdownButton<String>(
                  value: sortby,
                  onChanged: (String newValue) {
                    setState(() {
                      sortby = newValue;
                    });
                  },
                  items: [
                    DropdownMenuItem(
                      value: 'namn',
                      child: Text('Namn'),
                    ),
                    DropdownMenuItem(
                      value: 'beskrivning',
                      child: Text('Titel'),
                    )
                  ]
              ),
              Stack(
                children: <Widget>[
                  Visibility(
                    visible: decending,
                    child: IconButton(
                      icon: Icon(Icons.arrow_upward),
                      onPressed: () => setState(() {
                        decending = false;
                      }),
                    ),
                  ),
                  Visibility(
                    visible: !decending,
                    child: IconButton(
                      icon: Icon(Icons.arrow_downward),
                      onPressed: () => setState(() {
                        decending = true;
                      }),
                    ),
                  )
                ],
              )
            ],
          ),
          Expanded(
            child: Container(
              child: StreamBuilder(
                stream: Firestore.instance.collection('kontakt').orderBy(sortby, descending: decending).snapshots(), //Hämtar data från databas
                builder: (context, snapshot) {
                  //För att inte skriva över existerande lista:
                  if (showInfo == null) {
                    //Listan genereras här för att slippa kalla på databasen två ggr
                    showInfo = List.generate(snapshot.data.documents.length, (index) => false);
                  }
                  if (!snapshot.hasData) {
                    return Container();
                  } else if (snapshot.hasData) {
                    print(snapshot.data.documents.length);
                    return ListView.builder(
                      itemCount: snapshot.data.documents.length,
                      itemBuilder: (context, index) =>
                          _personer(context, snapshot.data.documents[index], index),
                    );
                  } else {
                    return Center(
                      child: Text("Error"),
                    );
                  }
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:2)

我相信是因为这一行:

if (showInfo == null) {
  showInfo = List.generate(snapshot.data.documents.length, (index) => false);
}

showInfo列表仅根据提供的条件一次进行更新。首先,showInfonull,因此它会被更新。在连续重建时,列表不再更新,因为它不再等于null。尝试删除if条件,看看会发生什么。