【问题标题】:Flutter, how do I correctly declare and use variables in a stateful widget?Flutter,如何在有状态小部件中正确声明和使用变量?
【发布时间】:2021-05-19 10:56:57
【问题描述】:

我有一个StatefulWidget,其中包含一个ListView() 和一个ListView.builder()ListView.builder() 使用两个列表构建多个 CheckboxListTile(),一个用于标签,一个用于布尔值。但是它没有按预期工作。我试图创建一个问题的最小示例,它看起来像这样:

import 'package:flutter/material.dart';

class TestClass extends StatefulWidget {
  @override
  _TestClassState createState() => _TestClassState();
}

class _TestClassState extends State<TestClass> {
  @override
  Widget build(BuildContext context) {
    bool firstBoolean = false;
    bool secondBoolean = false;
    List labels = [
    "First Checkbox",
    "Second Checkbox",
    ];  
    List<bool> booleans = [
      firstBoolean,
      secondBoolean,
    ];    
    return ListView(
      children: [
        Container(
          height: MediaQuery.of(context).size.height * 0.5,
          child: ListView.builder(
              physics: AlwaysScrollableScrollPhysics(),
              shrinkWrap: true,
              itemCount: 2,
              itemBuilder: (context, index) {
                return CheckboxListTile(
                  title: Text("${labels[index]}"),
                  value: booleans[index],
                  onChanged: (bool newValue) {
                    setState(() {
                      secondBoolean = newValue;
                      print(
                          "firstBoolean, secondBoolean: [$firstBoolean, $secondBoolean]");
                    });
                  },
                );
              }),
            ),
          ],
        );
      }
    }

这不会更改复选框,也不会更改分配的布尔值。如果我替换这一行:

value: booleans[index]

value: firstBoolean

并将bool firstBoolean = false; 移动到_TestCassState 中的@override 上方它“有效”,但由于所有复选框现在都分配了相同的布尔变量,因此它会同时更改所有复选框。但我不明白为什么这“有效”而上面的代码没有。此外,如果我尝试在@override 上方创建我需要的所有布尔值,然后尝试创建一个包含所有这些布尔值的列表,我会收到此错误:

实例成员“firstBoolean”无法在 初始化器。尝试将实例成员的引用替换为 不同的表达方式

如果我使用@override 上方的标签移动到列表,它不会给我这个错误并正确分配标签

我觉得我不了解 StatefulWidgets 的一些基本知识。所以如果有人能给我解释如何正确解决这个问题以及为什么这不能按预期工作,我真的很感激

【问题讨论】:

    标签: flutter dart statefulwidget


    【解决方案1】:

    您甚至不需要单独的布尔变量。

    您基本上可以将您的labels 包含在您的TestClass 中,因为它们不是状态的一部分,因为它们永远不会改变。

    接下来,您可以在 State 类中只使用 List&lt;bool&gt; booleans,因为所有更改的内容都只是这些 booleans 本身。

    所以你的结构现在是这样的。

    class TestClass extends StatefulWidget {
      final List labels = [
        "First Checkbox",
        "Second Checkbox",
      ];
      
      @override
      _TestClassState createState() => _TestClassState();
    }
    

    将它们放在StatefulWidget 类中是一种很好的做法。然后,您可以像这样在 State 类中使用它们 - widget.labels[index]

    所以,您的 State 课程将是,

    class _TestClassState extends State<TestClass> {
      List<bool> booleans = [false,false];
    
      @override
      Widget build(BuildContext context) {
        return ListView(
          children: [
            Container(
              height: MediaQuery.of(context).size.height * 0.5,
              child: ListView.builder(
                physics: AlwaysScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount: 2,
                itemBuilder: (context, index) {
                  return CheckboxListTile(
                    title: Text("${widget.labels[index]}"),
                    value: booleans[index],
                    onChanged: (bool newValue) {
                      setState(() {
                        // There was a logic error here in your code, so changed it to work correctly
                        booleans[index] = newValue;
                    });
                  },
                );
              }),
            ),
          ],
        );
      }
    }
    

    【讨论】:

      【解决方案2】:

      当您调用 setstate() 时,会调用 build 方法,并在 build 方法中声明您。

      覆盖initState() 状态方法。

      class _TestClassState extends State<TestClass> {
         bool firstBoolean,secondBoolean;
         List labels;
         List<bool> booleans;
        
        @override
         void initState(){
          super.initState();
             firstBoolean = false;
           secondBoolean = false;
           labels = [
          "First Checkbox",
          "Second Checkbox",
          ];  
          booleans = [
            firstBoolean,
            secondBoolean,
          ];    
        }
      }
      

      并从构建方法中删除变量声明

      【讨论】:

        【解决方案3】:

        每当您调用 setState() 方法时,都会调用构建函数并使用相同的旧值初始化变量。 解决问题的最简单方法是将变量排除在构建函数之外,这样每次调用 setState() 方法时它们就不会被初始化。 这是你应该做的事情

            import 'package:flutter/material.dart';
        class TestClass extends StatefulWidget {
          @override
          _TestClassState createState() => _TestClassState();
        }
        
        class _TestClassState extends State<TestClass> {
            // Declare the variables above build fucntion
            bool firstBoolean = false; 
            bool secondBoolean = false;
            List labels = [
            "First Checkbox",
            "Second Checkbox",
            ];  
            List<bool> booleans = [false,false];    
          @override
          Widget build(BuildContext context) {
            return ListView(
              children: [
                Container(
                  height: MediaQuery.of(context).size.height * 0.5,
                  child: ListView.builder(
                      physics: AlwaysScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: 2,
                      itemBuilder: (context, index) {
                        return CheckboxListTile(
                          title: Text("${labels[index]}"),
                          value: booleans[index],
                          onChanged: (bool newValue) {
                            setState(() {
                              secondBoolean = newValue;
                              print(
                                  "firstBoolean, secondBoolean: [$firstBoolean, $secondBoolean]");
                            });
                          },
                        );
                      }),
                    ),
                  ],
                );
              }
            }
        

        【讨论】:

          【解决方案4】:

          您在错误的位置声明了变量,您已经在构建函数中初始化了这些变量。因此,每当您调用 setState 时,该变量都会重新初始化为默认值。您也不需要使用firstBooleansecondBoolean。将您的代码更改为:

          class TestClass extends StatefulWidget {
            @override
            _TestClassState createState() => _TestClassState();
          }
          
          class _TestClassState extends State<TestClass> {
          
            List labels = [
              "First Checkbox",
              "Second Checkbox",
            ];
            List<bool> booleans = List.filled(2, false); // Initialising with default value
          
            @override
            Widget build(BuildContext context) {
              return ListView(
                children: [
                  Container(
                    height: MediaQuery.of(context).size.height * 0.5,
                    child: ListView.builder(
                      physics: AlwaysScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: 2,
                      itemBuilder: (context, index) {
                        return CheckboxListTile(
                          title: Text("${labels[index]}"),
                          value: booleans[index],
                          onChanged: (bool newValue) {
                            setState(() {
                              booleans[index] = newValue;
                              print(booleans[index]);
                            });
                          },
                        );
                      },
                    ),
                  ),
                ],
              );
            }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-05-14
            • 1970-01-01
            • 2023-04-01
            • 1970-01-01
            • 2020-02-19
            • 1970-01-01
            • 2017-12-16
            • 1970-01-01
            相关资源
            最近更新 更多