无法在 setState() 上重新加载 Flutter 小部件

Unable to reload Flutter widget on setSate()

我正在构建我的第一个 flutter 应用程序(也是我的第一个移动应用程序),但我很难理解如何重新加载页面(更改状态)。

我看了文档,也搜索了一些与我的相关的问题,但我仍然无法解决这个问题,因为根据具体问题的不同,改变状态的方法有很多。

所以,我有这个屏幕:

import 'package:flutter/material.dart';
import 'package:mobile_tech_overdose/models/categories.dart';
import 'package:mobile_tech_overdose/models/subcategories.dart';
import 'package:mobile_tech_overdose/services/api/category_api.dart';
import 'package:mobile_tech_overdose/services/api/subcategory_api.dart';

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);


  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  CategoryApi categoryApi = CategoryApi();
  SubcategoryApi subcategoryApi = SubcategoryApi();
  late Future<List<Category>> futureCategories;
  late Future<List<Subcategory>> futureSubcategoriesFromCategory;
  int? category_id;

  @override
  void initState() {
    super.initState();
    futureCategories = categoryApi.fetchCategories();
    futureSubcategoriesFromCategory = subcategoryApi.fetchSubcategoriesFromCategory(category_id);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Forum Categories'),
        ),
        body: Column(
          children: [
            SizedBox(
              height: 100,
              child: FutureBuilder<List<Category>>(
                  future: futureCategories,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      return ListView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: snapshot.data!.length,
                          itemBuilder: (context, index) {
                            Category category = snapshot.data![index];
                            return Container(
                              height: 200,
                              width: 200,
                              margin: const EdgeInsets.only(top: 20, left: 40),
                              child: ListTile(
                                title: ElevatedButton(
                                  child: Text(category.name),
                                  onPressed: () {
                                    setState(() {
                                      category_id = category.id;
                                    });
                                  },
                                ),
                              ),
                            );
                          });
                    } else if (snapshot.hasError) {
                      return const Text('Something went wrong');
                    }

                    return const Center(
                        child: CircularProgressIndicator()
                    );
                  }),
            ),
            Expanded(
              child: FutureBuilder<List<Subcategory>>(
                  future: futureSubcategoriesFromCategory,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      return ListView.builder(
                          scrollDirection: Axis.vertical,
                          itemCount: snapshot.data!.length,
                          itemBuilder: (context, index) {
                            Subcategory subcategory = snapshot.data![index];
                            return Center(
                              child: Padding(
                                padding: const EdgeInsets.all(10.0),
                                child: Card(
                                  color: Colors.black45,
                                  child: InkWell(
                                      splashColor: Colors.blue.withAlpha(50),
                                      onTap: () {
                                        debugPrint('Card');
                                      },
                                    child: Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Column(
                                        mainAxisSize: MainAxisSize.min,
                                        children: <Widget>[
                                          ListTile(
                                            leading: Padding(
                                              padding: const EdgeInsets.only(right: 10.0),
                                              child: Container(
                                                  width: 50.0,
                                                  height: 100.0,
                                                  decoration: BoxDecoration(
                                                      color: Colors.white,
                                                      shape: BoxShape.circle,
                                                      image: DecorationImage(
                                                          fit: BoxFit.fitHeight,
                                                          image: NetworkImage(
                                                              subcategory.photo_url)
                                                      )
                                                  )
                                              ),
                                            ),
                                            title: Padding(
                                              padding: const EdgeInsets.only(bottom: 4.0),
                                              child: Text(
                                                  subcategory.name,
                                                  style: const TextStyle(
                                                      fontWeight: FontWeight.bold,
                                                      color: Colors.black87
                                                  )
                                              ),
                                            ),
                                            subtitle: Padding(
                                              padding: const EdgeInsets.only(top: 4.0, bottom: 4.0),
                                              child: Text.rich(
                                                TextSpan(
                                                  text: 'Last Topic: ',
                                                  style: const TextStyle(
                                                    fontWeight: FontWeight.bold,
                                                    color: Colors.black54
                                                  ),
                                                  children: <TextSpan>[
                                                    TextSpan(
                                                        text: subcategory.latest_topic!,
                                                        style: const TextStyle(color: Colors.white70)
                                                    )
                                                  ],
                                                )
                                              ),
                                            ),
                                            // subtitle: Text(
                                            //     'Last Topic: ${subcategory.latest_topic!}',
                                            //     style: TextStyle(
                                            //         color: Colors.white,
                                            //         fontWeight: FontWeight.bold
                                            //     )
                                            // ),
                                          ),
                                          Row(
                                            mainAxisAlignment: MainAxisAlignment.end,
                                            children: <Widget>[
                                              RichText(
                                                text: TextSpan(
                                                  children: [
                                                    const WidgetSpan(
                                                      child: Icon(Icons.live_help, size: 20, color: Colors.redAccent,),
                                                    ),
                                                    TextSpan(
                                                      text: " ${subcategory.topics_count}",
                                                      semanticsLabel: "Topics count"
                                                    ),
                                                  ],
                                                ),
                                              ),
                                              const SizedBox(width: 8),
                                              RichText(
                                                text: TextSpan(
                                                  children: [
                                                    const WidgetSpan(
                                                      child: Icon(Icons.question_answer, size: 20, color: Colors.redAccent,),
                                                    ),
                                                    TextSpan(
                                                        text: " ${subcategory.comments_count}",
                                                        semanticsLabel: "Topics count"
                                                    ),
                                                  ],
                                                ),
                                              ),
                                              const SizedBox(width: 8),
                                            ],
                                          ),
                                        ],
                                      ),
                                    ),
                                  ),
                                ),
                              ),
                            );
                          });
                    } else if (snapshot.hasError) {
                      return const Text('Something went wrong');
                    }

                    return const Center(
                        child: CircularProgressIndicator()
                    );
                  }),
            ),
          ],
        ));
  }
}

如您所见,我在第一个 ListView.builder ElevatedButton 上调用 setState() 以更新 category_id 值。该 var 的目的是针对第二个 ListView.builder(futureSubcategoriesFromCategory = subcategoryApi.fetchSubcategoriesFromCategory(category_id);)。 但我可能做错了什么,因为小部件没有重新加载。

谁能帮帮我?

setState 将重建屏幕,即构建函数将再次调用,您将更改第二个 ListView.builder 的代码在 initState 中,因此它不会得到使用 category_id

的新值再次执行

快速解决方法是将其添加到您的 setState

futureSubcategoriesFromCategory = subcategoryApi.fetchSubcategoriesFromCategory(category.id);