Flutter 当按下按钮时,如何从ListView中删除文本字段?
当用户单击“清除图标”按钮时,如何删除文本字段?(不仅仅是清除TextField的文本) 用户故事Flutter 当按下按钮时,如何从ListView中删除文本字段?,flutter,dart,Flutter,Dart,当用户单击“清除图标”按钮时,如何删除文本字段?(不仅仅是清除TextField的文本) 用户故事 用户单击按钮添加播放器。(从技术上讲,此按钮添加文本字段) 用户可以在文本字段中写入播放器的名称。 用户点击“清除图标”按钮删除当前文本字段(与添加功能相反) 例如,用户在播放器4上设置“John”,如果用户单击“清除按钮”,则播放器4文本字段将被删除。它将只保留4个文本字段 您可以使用一个属性来检查用户是否单击了该按钮,这取决于显示/隐藏文本字段的值。下面我只使用一个布尔属性,如果用户单击X按
用户单击按钮添加播放器。(从技术上讲,此按钮添加文本字段)
用户可以在文本字段中写入播放器的名称。
用户点击“清除图标”按钮删除当前文本字段(与添加功能相反) 例如,用户在播放器4上设置“John”,如果用户单击“清除按钮”,则播放器4文本字段将被删除。它将只保留4个文本字段
您可以使用一个属性来检查用户是否单击了该按钮,这取决于显示/隐藏
文本字段的值。下面我只使用一个布尔属性,如果用户单击X按钮,那么我将hideField
设置为true,并且TextField
将替换为零大小的小部件
new ListView.builder(
padding: EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: 5,
itemBuilder: (context, index) {
print(index);
bool hideField = false; // I added it here
return hideField ? SizedBox.shrink() : TextField(
maxLength: 20,
decoration: InputDecoration(
labelText: "Player ${index + 1}",
counterText: "",
prefixIcon: const Icon(Icons.person),
suffixIcon: new IconButton(
icon: Icon(Icons.clear),
onPressed: () =>
setState(() {
hideField = true; // Now it works
})
),
),
);
}
)
我假设的事实:
您希望能够从列表中删除(或添加)字段
您希望在删除字段时保留其余字段的值
列表可以大于5
解决方案:
如果您希望上述所有内容都为真,那么您实际上需要跟踪文本字段的TextEditingController
s,而不是文本字段本身。这是因为TextField的值实际上存储在TextEditingController中(如果不为每个小部件提供它,则会动态地重新创建)。看看这个:
import 'package:flutter/material.dart';
// needs to be StatefulWidget, so we can keep track of the count of the fields internally
class PlayerList extends StatefulWidget {
const PlayerList({
this.initialCount = 5,
});
// also allow for a dynamic number of starting players
final int initialCount;
@override
_PlayerListState createState() => _PlayerListState();
}
class _PlayerListState extends State<PlayerList> {
int fieldCount = 0;
int nextIndex = 0;
// you must keep track of the TextEditingControllers if you want the values to persist correctly
List<TextEditingController> controllers = <TextEditingController>[];
// create the list of TextFields, based off the list of TextControllers
List<Widget> _buildList() {
int i;
// fill in keys if the list is not long enough (in case we added one)
if (controllers.length < fieldCount) {
for (i = controllers.length; i < fieldCount; i++) {
controllers.add(TextEditingController());
}
}
i = 0;
// cycle through the controllers, and recreate each, one per available controller
return controllers.map<Widget>((TextEditingController controller) {
int displayNumber = i + 1;
i++;
return TextField(
controller: controller,
maxLength: 20,
decoration: InputDecoration(
labelText: "Player $displayNumber",
counterText: "",
prefixIcon: const Icon(Icons.person),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
// when removing a TextField, you must do two things:
// 1. decrement the number of controllers you should have (fieldCount)
// 2. actually remove this field's controller from the list of controllers
setState(() {
fieldCount--;
controllers.remove(controller);
});
},
),
),
);
}).toList(); // convert to a list
}
@override
Widget build(BuildContext context) {
// generate the list of TextFields
final List<Widget> children = _buildList();
// append an 'add player' button to the end of the list
children.add(
GestureDetector(
onTap: () {
// when adding a player, we only need to inc the fieldCount, because the _buildList()
// will handle the creation of the new TextEditingController
setState(() {
fieldCount++;
});
},
child: Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
'add player',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
);
// build the ListView
return ListView(
padding: EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: children,
);
}
@override
void initState() {
super.initState();
// upon creation, copy the starting count to the current count
fieldCount = widget.initialCount;
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(PlayerList oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
}
导入“包装:颤振/材料.省道”;
//需要是StatefulWidget,以便我们可以在内部跟踪字段的计数
类PlayerList扩展StatefulWidget{
康斯特剧作家({
这个.initialCount=5,
});
//同时考虑到起始球员的动态数量
最终整数初始计数;
@凌驾
_PlayerListState createState()=>PlayerListState();
}
类_PlayerListState扩展状态{
int fieldCount=0;
int-nextIndex=0;
//如果希望值正确持久,则必须跟踪TextEditingController
列表控制器=[];
//根据TextController列表创建TextFields列表
列表_buildList(){
int i;
//如果列表不够长,请填写关键字(如果我们添加了一个)
if(controllers.length
通过以上步骤,您可以:
- 启动应用程序
- 将播放器2更改为“bob”
- 将播放器3更改为“史蒂夫”
- 将播放器4更改为“charles”
- 删除播放器3
- 观察玩家2是“鲍勃”,而新玩家3是“查尔斯”
我想这就是您在这里要找的。这将有两个问题。1.您只能有5个文本字段,2个。删除其中一个字段时,其他字段的值将不会以正确的顺序保留。不,不会有问题。1.注意,我只是更新当前文本字段2的状态。其他人的价值将持续存在,因为我没有重建whilelistview,我只是用一个大小为零的小部件替换TextField。将它插入模拟器。我指出的两个问题是实际问题。非常感谢您的帮助,您的答案解释得很好:)我尝试过这样做:当用户单击“添加播放器”按钮时,自动滚动到底部页面。我添加了一个ScrollController,但不起作用ScrollController\u ScrollController
import 'package:flutter/material.dart';
// needs to be StatefulWidget, so we can keep track of the count of the fields internally
class PlayerList extends StatefulWidget {
const PlayerList({
this.initialCount = 5,
});
// also allow for a dynamic number of starting players
final int initialCount;
@override
_PlayerListState createState() => _PlayerListState();
}
class _PlayerListState extends State<PlayerList> {
int fieldCount = 0;
int nextIndex = 0;
// you must keep track of the TextEditingControllers if you want the values to persist correctly
List<TextEditingController> controllers = <TextEditingController>[];
// create the list of TextFields, based off the list of TextControllers
List<Widget> _buildList() {
int i;
// fill in keys if the list is not long enough (in case we added one)
if (controllers.length < fieldCount) {
for (i = controllers.length; i < fieldCount; i++) {
controllers.add(TextEditingController());
}
}
i = 0;
// cycle through the controllers, and recreate each, one per available controller
return controllers.map<Widget>((TextEditingController controller) {
int displayNumber = i + 1;
i++;
return TextField(
controller: controller,
maxLength: 20,
decoration: InputDecoration(
labelText: "Player $displayNumber",
counterText: "",
prefixIcon: const Icon(Icons.person),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
// when removing a TextField, you must do two things:
// 1. decrement the number of controllers you should have (fieldCount)
// 2. actually remove this field's controller from the list of controllers
setState(() {
fieldCount--;
controllers.remove(controller);
});
},
),
),
);
}).toList(); // convert to a list
}
@override
Widget build(BuildContext context) {
// generate the list of TextFields
final List<Widget> children = _buildList();
// append an 'add player' button to the end of the list
children.add(
GestureDetector(
onTap: () {
// when adding a player, we only need to inc the fieldCount, because the _buildList()
// will handle the creation of the new TextEditingController
setState(() {
fieldCount++;
});
},
child: Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
'add player',
style: TextStyle(
color: Colors.white,
),
),
),
),
),
);
// build the ListView
return ListView(
padding: EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: children,
);
}
@override
void initState() {
super.initState();
// upon creation, copy the starting count to the current count
fieldCount = widget.initialCount;
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(PlayerList oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
}