Flutter:从动态表单获取开关切换值或状态更改重建为何不同
Flutter: getting switch toggle values from dynamic form or why does state change rebuild differs
我有一种可以添加卡片的表单,每张卡片都有 5 个文本字段和 2 个开关。我想使用一种方法来构建开关代码(和文本字段代码,但这是有效的)。但是,开关拒绝显示其预期状态。我看到了几个类似的问题。然而,大多数问题都是通过一个列表视图解决的,列表视图将所有 switched/checkboxes 并排列出(我有多张卡片,每个卡片都有多个文本字段和多个开关)。 This 很接近,但我不太明白答案(在评论中)
实际上一些答案是相同的(我猜或多或少是因为我的不工作)代码将开关状态存储在 bool 列表中。调试时,我可以看到值已正确存储在列表中。但是,更改后的值不会在状态更改时呈现。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var descrTECs = <TextEditingController>[];
var fixedSCs = [true]; //storing the switch values
var cards = <Card>[]; // storing the list of cards with forms
SizedBox createTextField(String placeholderStr, double fieldWidth) {
var tFieldController = TextEditingController();
switch (placeholderStr) { //switching placeholder to assign text controller to correct controller list
case "Description":
descrTECs.add(tFieldController);
break;
}
return SizedBox(width: fieldWidth, height: 25,
child: CupertinoTextField(
placeholder: placeholderStr,
controller: tFieldController,
),
);
}
SizedBox createSwitch(int pos) {
return SizedBox(width: 50, height: 25,
child: CupertinoSwitch(
value: fixedSCs[pos],
onChanged: (value) {
setState(() => fixedSCs[pos] = value); // value is stored in fixedSCs but not rendered upon rebuild
},
)
);
}
Card createCard() {
return Card(
child: Row(children: <Widget>[
Text('#p${cards.length + 1}:'),
Column(
children: <Widget>[
createSwitch(cards.length),
createTextField("Description", 70.0),
],),
],),
);
}
@override
void initState() {
super.initState();
cards.add(createCard()); // first card created upon start
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder( // List Builder to show all cards
itemCount: cards.length,
itemBuilder: (BuildContext context, int index) {
return cards[index];
},
),
),
RaisedButton(
child: Text('add new'),
onPressed: () => setState(() {
fixedSCs.add(true); // bool element created to create next card
cards.add(createCard());} // create next card
),
),
],
),
),);
}
}
有一件事我一般不明白:状态改变后重建时 cards.length}
应该是我的卡片数量,比方说 3。当它渲染第一张卡片时,它通过了 Text("#p${cards.length + 1}")
,所以它应该显示#p3 而不是#p1。我在这里弄错了什么?
我同时通过相当多的逻辑更改使它工作。
我把 switch builder 放到一个无状态的 widget 中
class createSwitch extends StatelessWidget {
const createSwitch({
this.label, this.margin=const EdgeInsets.all(0.0), this.width, this.height, this.value, this.onChanged});
final String label; final EdgeInsets margin; final double width; final double height; final bool value;
final Function onChanged;
@override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Expanded(child: Text(label)),
CupertinoSwitch(
value: value,
onChanged: (bool newValue) {onChanged(newValue);},
),
],
),
),
} }
在父有状态控制器中,我创建了一个列表来存储开关的状态 var parameterSCs = [true];
,每次添加卡片时,我都会通过单击按钮添加一个值 onPressed: () => setState(() {parameterSCs.add(true);}
我不再将卡片小部件存储为列表。相反,我直接在 ListView.builder
中的代码中构建它们
ListView.builder(
itemCount: parameterSCs.length,
itemBuilder: (BuildContext context, int index) {
return Card( ...
在我的实际代码中,每张卡有 2 个开关,所以我总是添加 2 个元素,然后 ListView 计数是参数 SC 长度的一半。
我尝试了很多方法,这是唯一有效的方法
我有一种可以添加卡片的表单,每张卡片都有 5 个文本字段和 2 个开关。我想使用一种方法来构建开关代码(和文本字段代码,但这是有效的)。但是,开关拒绝显示其预期状态。我看到了几个类似的问题。然而,大多数问题都是通过一个列表视图解决的,列表视图将所有 switched/checkboxes 并排列出(我有多张卡片,每个卡片都有多个文本字段和多个开关)。 This 很接近,但我不太明白答案(在评论中)
实际上一些答案是相同的(我猜或多或少是因为我的不工作)代码将开关状态存储在 bool 列表中。调试时,我可以看到值已正确存储在列表中。但是,更改后的值不会在状态更改时呈现。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var descrTECs = <TextEditingController>[];
var fixedSCs = [true]; //storing the switch values
var cards = <Card>[]; // storing the list of cards with forms
SizedBox createTextField(String placeholderStr, double fieldWidth) {
var tFieldController = TextEditingController();
switch (placeholderStr) { //switching placeholder to assign text controller to correct controller list
case "Description":
descrTECs.add(tFieldController);
break;
}
return SizedBox(width: fieldWidth, height: 25,
child: CupertinoTextField(
placeholder: placeholderStr,
controller: tFieldController,
),
);
}
SizedBox createSwitch(int pos) {
return SizedBox(width: 50, height: 25,
child: CupertinoSwitch(
value: fixedSCs[pos],
onChanged: (value) {
setState(() => fixedSCs[pos] = value); // value is stored in fixedSCs but not rendered upon rebuild
},
)
);
}
Card createCard() {
return Card(
child: Row(children: <Widget>[
Text('#p${cards.length + 1}:'),
Column(
children: <Widget>[
createSwitch(cards.length),
createTextField("Description", 70.0),
],),
],),
);
}
@override
void initState() {
super.initState();
cards.add(createCard()); // first card created upon start
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder( // List Builder to show all cards
itemCount: cards.length,
itemBuilder: (BuildContext context, int index) {
return cards[index];
},
),
),
RaisedButton(
child: Text('add new'),
onPressed: () => setState(() {
fixedSCs.add(true); // bool element created to create next card
cards.add(createCard());} // create next card
),
),
],
),
),);
}
}
有一件事我一般不明白:状态改变后重建时 cards.length}
应该是我的卡片数量,比方说 3。当它渲染第一张卡片时,它通过了 Text("#p${cards.length + 1}")
,所以它应该显示#p3 而不是#p1。我在这里弄错了什么?
我同时通过相当多的逻辑更改使它工作。
我把 switch builder 放到一个无状态的 widget 中
class createSwitch extends StatelessWidget {
const createSwitch({
this.label, this.margin=const EdgeInsets.all(0.0), this.width, this.height, this.value, this.onChanged});
final String label; final EdgeInsets margin; final double width; final double height; final bool value;
final Function onChanged;
@override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Expanded(child: Text(label)),
CupertinoSwitch(
value: value,
onChanged: (bool newValue) {onChanged(newValue);},
),
],
),
),
} }
在父有状态控制器中,我创建了一个列表来存储开关的状态 var parameterSCs = [true];
,每次添加卡片时,我都会通过单击按钮添加一个值 onPressed: () => setState(() {parameterSCs.add(true);}
我不再将卡片小部件存储为列表。相反,我直接在 ListView.builder
中的代码中构建它们ListView.builder(
itemCount: parameterSCs.length,
itemBuilder: (BuildContext context, int index) {
return Card( ...
在我的实际代码中,每张卡有 2 个开关,所以我总是添加 2 个元素,然后 ListView 计数是参数 SC 长度的一半。
我尝试了很多方法,这是唯一有效的方法