如何解决Flutter,如何在有状态小部件中正确声明和使用变量?
我有一个 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;
移动到 @override
中的 _TestCassstate
上方它“有效”但由于现在所有复选框都分配了相同的布尔变量,因此在同时。但我不明白为什么这个“有效”而上面的代码却没有。此外,如果我尝试在 @override
上方创建我需要的所有布尔值,然后尝试创建包含所有这些的列表,我会收到此错误:
实例成员 'firstBoolean' 不能在 初始化程序。尝试用 a 替换对实例成员的引用 不同的表达
如果我使用 @override
上方的标签移动到 List,它不会给我这个错误并正确分配标签
我觉得我没有理解 StatefulWidgets 的一些基本知识。因此,如果有人能给我解释如何正确解决这个问题以及为什么这不能按预期工作,我真的很感激
解决方法
每当您调用 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,];
}
}
并从构建方法中删除变量声明
,您甚至不需要单独的 bool 变量。
您基本上可以将您的 labels
放在您的 TestClass
中,因为它们不是状态的一部分,因为它们永远不会改变。
接下来,您可以在 List<bool> booleans
类中只使用 State
,因为所有更改的内容都只是这些 booleans
本身。
所以你的结构现在会是这样。
class TestClass extends StatefulWidget {
final List labels = [
"First 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;
});
},);
}),),],);
}
}
,
每当您调用 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",];
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(),index) {
return CheckboxListTile(
title: Text("${labels[index]}"),onChanged: (bool newValue) {
setState(() {
secondBoolean = newValue;
print(
"firstBoolean,secondBoolean: [$firstBoolean,$secondBoolean]");
});
},);
}),);
}
}
,
您在错误的地方声明了变量,您已经在构建函数中初始化了这些变量。因此,每当您调用 setState 时,变量都会重新初始化为默认值。此外,您不需要使用 firstBoolean
和 secondBoolean
。将您的代码更改为:
class TestClass extends StatefulWidget {
@override
_TestClassState createState() => _TestClassState();
}
class _TestClassState extends State<TestClass> {
List labels = [
"First 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,index) {
return CheckboxListTile(
title: Text("${labels[index]}"),onChanged: (bool newValue) {
setState(() {
booleans[index] = newValue;
print(booleans[index]);
});
},);
},);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。