flutter 在FutureBuilder内部设置状态

n3ipq98p  于 2023-01-14  发布在  Flutter
关注(0)|答案(2)|浏览(156)

我正在设计一个带有文档列表的屏幕,我决定使用页眉上的ToggleButtons根据文档发布的年份来过滤文档。
文档的信息是从一个URL加载的,我用FutureBuilder来构建屏幕。当我点击一个ToggleButton时,setState不起作用,它不更新屏幕。我不知道为什么。
那样就不可能过滤文件了。
我分享代码:

class ListOfDocuments extends StatefulWidget {
  final SingleItem singleItem;
  final String sectionRowName;
  const ListOfDocuments(
      {Key? key, required this.singleItem, required this.sectionRowName})
      : super(key: key);

  @override
  State<ListOfDocuments> createState() => _ListOfDocumentsState();
}

class _ListOfDocumentsState extends State<ListOfDocuments> {
  // Iniciamos el servicio para pedir a la web la información.
  final HttpService httpService = HttpService();
  // Iniciamos la variable donde almacenaremos los documentos.
  Future<List<Document>>? listadoDocumentos;
  // Obtenemos el código del idioma utilizado.
  String myLocale = Intl.getCurrentLocale();

  // Cargamos documentos.
  void cargarDocumentos() async {
    // Pedimos el listado de documentos.
    listadoDocumentos = httpService.getDocList(
      myLocale.toString(),
      widget.sectionRowName,
      widget.singleItem,
    );
  }

  @override
  void initState() {
    super.initState();
    // Cargamos los documentos al iniciar.
    cargarDocumentos();
  }

  @override
  Widget build(BuildContext context) {
    // Screen size.
    double screenWidth = MediaQuery.of(context).size.width;
    double screenHeight = MediaQuery.of(context).size.height;
    // For ToggleButtons.
    List<Widget> years = <Widget>[
      Padding(
        padding: const EdgeInsets.all(4.0),
        child: Text(S.of(context).all),
      ),
      const Text("2005"),
      const Text("2006"),
      const Text("2007"),
      const Text("2008"),
      const Text("2009"),
      const Text("2010"),
      const Text("2011"),
      const Text("2012"),
      const Text("2013"),
    ];
    List<bool> selectedYear = <bool>[
      true,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false
    ];

    return Scaffold(
      backgroundColor: kPrimaryColor,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0.0,
        centerTitle: true,
        title: getTitle(widget.sectionRowName, widget.singleItem.name, context),
      ),
      body: FutureBuilder(
        future: listadoDocumentos,
        builder: (BuildContext context, AsyncSnapshot snapshotFromList) {
          if (snapshotFromList.hasData) {
            // Hacemos una lista de titulos con fechas.
            List<Document> docList = List.generate(
              snapshotFromList.data.length,
              (index) => Document(
                id: snapshotFromList.data[index].id,
                fecha: snapshotFromList.data[index].fecha,
                titulo: snapshotFromList.data[index].titulo,
              ),
            );

            return Column(
              children: [
                SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: Padding(
                    padding: const EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0),
                    child: ToggleButtons(
                      direction: Axis.horizontal,
                      textStyle: kAppBarStyle.copyWith(fontSize: 18.0),
                      borderColor: Colors.yellow,
                      borderWidth: 1.0,
                      selectedBorderColor: Colors.yellowAccent,
                      fillColor: Colors.yellowAccent.withOpacity(0.2),
                      color: Colors.white,
                      selectedColor: Colors.white,
                      isSelected: selectedYear,
                      borderRadius:
                          const BorderRadius.all(Radius.circular(10.0)),
                      onPressed: (int index) {
                        setState(() {
                          // The button that is tapped is set to true, and the others to false.
                          for (int i = 0; i < selectedYear.length; i++) {
                            selectedYear[i] = i == index;
                          }
                        });
                      },
                      children: years,
                    ),
                  ),
                ),
                Expanded(
                  child: Padding(
                    padding:
                        EdgeInsets.fromLTRB(0.0, 0.0, screenWidth * 0.05, 0.0),
                    child: SingleChildScrollView(
                      scrollDirection: Axis.vertical,
                      child: ListView.separated(
                        itemCount: docList.length,
                        shrinkWrap: true,
                        physics: const NeverScrollableScrollPhysics(),
                        separatorBuilder: (BuildContext context, int index) {
                          return const Divider(
                            thickness: 2.0,
                            color: Colors.white10,
                            indent: 15.0,
                          );
                        },
                        itemBuilder: (context, index) {
                          DateTime dateFormated = DateFormat('dd/MM/yyyy')
                              .parse(docList[index].fecha);
                          return ListTile(
                            leading: Column(
                              crossAxisAlignment: CrossAxisAlignment.center,
                              mainAxisAlignment: MainAxisAlignment.center,
                              mainAxisSize: MainAxisSize.max,
                              children: [
                                Text(
                                  DateFormat("dd").format(dateFormated),
                                  style: kDocTitleInList.copyWith(
                                    color: Colors.white70,
                                  ),
                                ),
                                Text(
                                  DateFormat("MMM")
                                      .format(dateFormated)
                                      .toUpperCase(),
                                  style: kDocTitleInList.copyWith(
                                    fontSize: 10.0,
                                    color: Colors.white70,
                                  ),
                                ),
                                Text(
                                  DateFormat("yyyy").format(dateFormated),
                                  style: kDocTitleInList.copyWith(
                                    fontSize: 14.0,
                                    color: Colors.white70,
                                  ),
                                ),
                              ],
                            ),
                            title: Text(
                              docList[index].titulo,
                              style: kDocTitleInList,
                            ),
                            trailing: const Icon(
                              Icons.arrow_forward_ios_rounded,
                              color: Colors.white,
                            ),
                            onTap: () {
                              showDialog(
                                context: context,
                                builder: (BuildContext context) {
                                  return FutureBuilder(
                                      // Pedimos a la web el documento por el "id".
                                      future: httpService.getDocument(
                                          snapshotFromList.data[index].id
                                              .toString()),
                                      builder: (BuildContext context,
                                          AsyncSnapshot snapshotFromDocument) {
                                        if (snapshotFromDocument.hasData) {
                                          return Dialog(
                                            backgroundColor: Colors.transparent,
                                            elevation: 0.0,
                                            child: Container(
                                              decoration: BoxDecoration(
                                                color: Colors.white,
                                                borderRadius:
                                                    BorderRadius.circular(30.0),
                                              ),
                                              child: Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.center,
                                                mainAxisSize: MainAxisSize.min,
                                                children: <Widget>[
                                                  Padding(
                                                    padding:
                                                        const EdgeInsets.all(
                                                            15.0),
                                                    child: Text(
                                                      snapshotFromList
                                                          .data[index].titulo,
                                                      style: kSubTitleStyle
                                                          .copyWith(
                                                              color:
                                                                  Colors.black),
                                                    ),
                                                  ),
                                                  Padding(
                                                    padding:
                                                        const EdgeInsets.all(
                                                            15.0),
                                                    child: FlagChips(
                                                        documento:
                                                            snapshotFromDocument
                                                                .data),
                                                  ),
                                                  GestureDetector(
                                                    child: Text(
                                                      '- ${S.of(context).cerrarVentana} -',
                                                      style: kSubTitleStyle
                                                          .copyWith(
                                                              color:
                                                                  Colors.black),
                                                    ),
                                                    onTap: () {
                                                      Navigator.of(context)
                                                          .pop();
                                                    },
                                                  ),
                                                  const SizedBox(
                                                    height: 20.0,
                                                  ),
                                                ],
                                              ),
                                            ),
                                          );
                                        } else {
                                          return const Center(
                                            child: CircularProgressIndicator(
                                              color: Colors.white54,
                                            ),
                                          );
                                        }
                                      });
                                },
                              );
                            },
                          );
                        },
                      ),
                    ),
                  ),
                ),
              ],
            );
          } else {
            return const Center(
              child: CircularProgressIndicator(
                color: Colors.white54,
              ),
            );
          }
        },
      ),
    );
  }
}
unftdfkk

unftdfkk1#

问题是selectedYear变量是在build函数的作用域中声明的。因为这是有状态小部件的“状态”,所以应该在_ListOfDocumentsState的主体中声明。只需将此变量移出build,与httpServicelistadoDocumentosmyLocale变量放在一起。

class _ListOfDocumentsState extends State<ListOfDocuments> {
  ...(other function and variable declarations)

  List<bool> selectedYear = <bool>[
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false
  ];

  @override
  Widget build(BuildContext context) {
    // Screen size.
    double screenWidth = MediaQuery.of(context).size.width;
    double screenHeight = MediaQuery.of(context).size.height;
    // For ToggleButtons.
    List<Widget> years = <Widget>[
      Padding(
        padding: const EdgeInsets.all(4.0),
        child: Text(S.of(context).all),
      ),
      const Text("2005"),
      const Text("2006"),
      const Text("2007"),
      const Text("2008"),
      const Text("2009"),
      const Text("2010"),
      const Text("2011"),
      const Text("2012"),
      const Text("2013"),
    ];
   ...(and the rest of your build function)

使用当前方法时,循环会按照您的意愿更新selectedYear列表,但是调用setState会再次调用build,这会将selectedYear重置为原始状态,第一个元素为true

s5a0g9ez

s5a0g9ez2#

您可以在Future方法上定义它,并在button上调用Future方法。

Future<String> _reloadState() {
    setState(() {});
}

你也可以从API获取数据,如果你已经调用了setState函数来重新加载你的状态。

相关问题