You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter添加数据后ListView未实时更新,仅热重载生效问题求助

问题:添加数据后ListView无法实时更新,需热重载才能显示

我尝试从BottomSheet获取数据存入ProductInfos模型,再在ListView中展示相关数据。目前流程看似正常,但添加新数据后无法实时显示在ListView中,必须热重载应用才能看到新增数据,且每次添加都需要重复热重载,尚未找到解决办法。

主页面代码

bool? isChecked = false;
final boy = TextEditingController();
final adet = TextEditingController();
final kilo = TextEditingController();

final firma = TextEditingController();
final kalit = TextEditingController();
final kalinlik = TextEditingController();
final en = TextEditingController();

class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    var size = MediaQuery.of(context).size;
    final productInfoProvider = ref.watch(productProvider);

    ProductInfos product1 = ProductInfos(
        firmAdi: firma.text,
        kalite: kalit.text,
        kalinlik: kalinlik.text,
        en: en.text,
        boy: boy.text,
        adet: adet.text,
        kilo: kilo.text,
        pvc: isChecked);
    ProductInfos product2 = ProductInfos(
        firmAdi: "firma.text",
        kalite: "kalit.text",
        kalinlik: "kalinlik.text",
        en: "en.text",
        boy: "boy.text",
        adet: "adet.text",
        kilo: "kilo.text",
        pvc: true);

    return Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Column(
          children: [
            SizedBox(
                height: size.height * 0.5,
                child: ListView.separated(
                  separatorBuilder: (context, index) {
                    return const Divider(
                      height: 5,
                      thickness: 2,
                    );
                  },
                  itemCount: productInfoProvider.products.length,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
                      color: Colors.white,
                      child: ListTile(
                        leading: Text(productInfoProvider
                            .products[index].firmAdi
                            .toString()),
                        subtitle: Text(
                            productInfoProvider.products[index].en.toString()),
                        title: Text(
                            "${productInfoProvider.products[index].kalite.toString()}  kalite"),
                      ),
                    );
                  },
                )),
            Center(
              child: SizedBox(
                  height: size.height * 0.2,
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.white,
                        foregroundColor: Colors.black),
                    onPressed: () {
                      print(productInfoProvider.products.length);

                      showModalBottomSheet(
                          context: context,
                          builder: ((context) {
                            return StatefulBuilder(
                                //bottomSheet de statefulbuilder kullanmazsak state yenilenmiyor
                                builder: (BuildContext context,
                                    StateSetter myState) {
                              return SizedBox(
                                height: size.height * 0.5,
                                child: Padding(
                                  padding: const EdgeInsets.all(10.0),
                                  child: Column(
                                    children: [
                                      Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.spaceBetween,
                                        children: [
                                          solBottomSheet(size, myState),
                                          sagBottomSheet(size, myState),
                                        ],
                                      ),
                                      Align(
                                          alignment: Alignment.bottomCenter,
                                          child: ElevatedButton(
                                            onPressed: (() {
                                              myState(() {
                                                ref
                                                    .read(productProvider)
                                                    .addProduct(product1);
                                                inspect(productInfoProvider
                                                    .products);
                                              });
                                            }),
                                            style: ElevatedButton.styleFrom(
                                                backgroundColor:
                                                    const Color(0xff74a6cc)),
                                            child: const Text("ekle"),
                                          )),
                                    ],
                                  ),
                                ),
                              );
                            });
                          }));
                    },
                    child: const Text("BottomSheet"),
                  )),
            ),
          ],
        ));
  }

  SizedBox sagBottomSheet(Size size, StateSetter myState) {
    return SizedBox(
        width: size.width * 0.4,
        child: Column(
          children: [
            CustomTextField(
              textController: boy,
              t: TextInputType.number,
              hintText: "Boy",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CustomTextField(
              textController: adet,
              t: TextInputType.number,
              hintText: "Adet",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CustomTextField(
              textController: kilo,
              t: TextInputType.number,
              hintText: "Kilo",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CheckboxListTile(
                title: const Text(
                  "PVC",
                  style: TextStyle(
                      color: Color(0xff74a6cc), fontWeight: FontWeight.w800),
                ),
                value: isChecked,
                onChanged: ((value) {
                  myState(
                    () {
                      isChecked = value;
                    },
                  );
                })),
          ],
        ));
  }

  SizedBox solBottomSheet(Size size, StateSetter myState) {
    return SizedBox(
      width: size.width * 0.4,
      child: Column(
        children: [
          CustomTextField(
            textController: firma,
            t: TextInputType.name,
            hintText: "Firma",
            ic: const Icon(Icons.home),
          ),
          space(),
          CustomTextField(
            textController: kalit,
            t: TextInputType.number,
            hintText: "Kalite",
            ic: const Icon(Icons.high_quality_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
          space(),
          CustomTextField(
            textController: kalinlik,
            t: TextInputType.number,
            hintText: "Kalınlık",
            ic: const Icon(Icons.high_quality_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
          space(),
          CustomTextField(
            textController: en,
            t: TextInputType.number,
            hintText: "En",
            ic: const Icon(Icons.numbers_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
        ],
      ),
    );
  }

  SizedBox space() {
    return const SizedBox(
      height: 10,
    );
  }
}

Provider代码

//this is provider code

class ProductInfoRepo extends ChangeNotifier {
  List<ProductInfos> products = [
    ProductInfos(
        firmAdi: "firm1",
        kalite: "430",
        kalinlik: "0.50",
        en: "750",
        boy: "1000",
        adet: "500",
        kilo: "1500",
        pvc: true),
    
  ];

  addProduct(ProductInfos product) {
    products.add(product);
    notifyListeners();
  }
}

final productProvider = ChangeNotifierProvider((((ref) {
  return ProductInfoRepo();
})));

解决方案

问题根源

  1. 全局变量导致状态不一致:isChecked和所有TextEditingController都是全局变量,脱离了Widget的生命周期管理,输入值更新无法同步到后续创建的ProductInfos实例。
  2. product1初始化时机错误:product1在build方法中创建,此时获取的是控制器的初始空值;用户在BottomSheet输入内容后,product1不会自动更新为最新输入值,添加的是空数据,热重载后build重新执行才会读取当前输入值,造成“热重载才显示”的假象。

修正后的主页面代码

class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    var size = MediaQuery.of(context).size;
    final productInfoProvider = ref.watch(productProvider);

    // 将控制器和复选框状态移至build内部,跟随Widget生命周期管理
    final boy = TextEditingController();
    final adet = TextEditingController();
    final kilo = TextEditingController();
    final firma = TextEditingController();
    final kalit = TextEditingController();
    final kalinlik = TextEditingController();
    final en = TextEditingController();
    bool? isChecked = false;

    return Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Column(
          children: [
            SizedBox(
                height: size.height * 0.5,
                child: ListView.separated(
                  separatorBuilder: (context, index) {
                    return const Divider(
                      height: 5,
                      thickness: 2,
                    );
                  },
                  itemCount: productInfoProvider.products.length,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
                      color: Colors.white,
                      child: ListTile(
                        leading: Text(productInfoProvider
                            .products[index].firmAdi
                            .toString()),
                        subtitle: Text(
                            productInfoProvider.products[index].en.toString()),
                        title: Text(
                            "${productInfoProvider.products[index].kalite.toString()}  kalite"),
                      ),
                    );
                  },
                )),
            Center(
              child: SizedBox(
                  height: size.height * 0.2,
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.white,
                        foregroundColor: Colors.black),
                    onPressed: () {
                      print(productInfoProvider.products.length);

                      showModalBottomSheet(
                          context: context,
                          builder: ((context) {
                            return StatefulBuilder(
                                builder: (BuildContext context,
                                    StateSetter myState) {
                              return SizedBox(
                                height: size.height * 0.5,
                                child: Padding(
                                  padding: const EdgeInsets.all(10.0),
                                  child: Column(
                                    children: [
                                      Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.spaceBetween,
                                        children: [
                                          // 传递控制器和状态更新回调
                                          solBottomSheet(size, firma, kalit, kalinlik, en),
                                          sagBottomSheet(size, boy, adet, kilo, (value) {
                                            myState(() {
                                              isChecked = value;
                                            });
                                          }, isChecked),
                                        ],
                                      ),
                                      Align(
                                          alignment: Alignment.bottomCenter,
                                          child: ElevatedButton(
                                            onPressed: (() {
                                              // 点击提交时才创建ProductInfos实例,获取最新输入值
                                              final newProduct = ProductInfos(
                                                firmAdi: firma.text,
                                                kalite: kalit.text,
                                                kalinlik: kalinlik.text,
                                                en: en.text,
                                                boy: boy.text,
                                                adet: adet.text,
                                                kilo: kilo.text,
                                                pvc: isChecked,
                                              );
                                              ref.read(productProvider).addProduct(newProduct);
                                              Navigator.pop(context); // 关闭BottomSheet,提升体验
                                            }),
                                            style: ElevatedButton.styleFrom(
                                                backgroundColor:
                                                    const Color(0xff74a6cc)),
                                            child: const Text("ekle"),
                                          )),
                                    ],
                                  ),
                                ),
                              );
                            });
                          }));
                    },
                    child: const Text("BottomSheet"),
                  )),
            ),
          ],
        ));
  }

  SizedBox sagBottomSheet(Size size, TextEditingController boy, TextEditingController adet, TextEditingController kilo, Function(bool?) onCheckboxChanged, bool? isChecked) {
    return SizedBox(
        width: size.width * 0.4,
        child: Column(
          children: [
            CustomTextField(
              textController: boy,
              t: TextInputType.number,
              hintText: "Boy",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CustomTextField(
              textController: adet,
              t: TextInputType.number,
              hintText: "Adet",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CustomTextField(
              textController: kilo,
              t: TextInputType.number,
              hintText: "Kilo",
              ic: const Icon(Icons.numbers_outlined),
              dgonly: [FilteringTextInputFormatter.digitsOnly],
            ),
            space(),
            CheckboxListTile(
                title: const Text(
                  "PVC",
                  style: TextStyle(
                      color: Color(0xff74a6cc), fontWeight: FontWeight.w800),
                ),
                value: isChecked,
                onChanged: onCheckboxChanged),
          ],
        ));
  }

  SizedBox solBottomSheet(Size size, TextEditingController firma, TextEditingController kalit, TextEditingController kalinlik, TextEditingController en) {
    return SizedBox(
      width: size.width * 0.4,
      child: Column(
        children: [
          CustomTextField(
            textController: firma,
            t: TextInputType.name,
            hintText: "Firma",
            ic: const Icon(Icons.home),
          ),
          space(),
          CustomTextField(
            textController: kalit,
            t: TextInputType.number,
            hintText: "Kalite",
            ic: const Icon(Icons.high_quality_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
          space(),
          CustomTextField(
            textController: kalinlik,
            t: TextInputType.number,
            hintText: "Kalınlık",
            ic: const Icon(Icons.high_quality_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
          space(),
          CustomTextField(
            textController: en,
            t: TextInputType.number,
            hintText: "En",
            ic: const Icon(Icons.numbers_outlined),
            dgonly: [FilteringTextInputFormatter.digitsOnly],
          ),
        ],
      ),
    );
  }

  SizedBox space() {
    return const SizedBox(
      height: 10,
    );
  }
}

核心修正点

  1. 将TextEditingController和isChecked移至build方法内部,跟随Widget生命周期管理,避免全局变量的状态混乱。
  2. 点击"ekle"按钮时才创建ProductInfos实例,确保获取的是用户输入后的最新值。
  3. 提交数据后关闭BottomSheet,优化用户交互体验。
  4. 将控制器和复选框状态回调作为参数传递给BottomSheet的子组件,保证状态更新同步。

内容的提问来源于stack exchange,提问作者Tolunay Kutlu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:15:42