Flutter:在设置状态后将数据保存在文本字段中
Flutter: keep data in textfield after setstate
- 我有一个文本字段数组。
- 向数组添加新文本字段的按钮。
- 如果您将数据添加到文本字段并通过单击添加按钮添加新元素,添加的数据将消失。
- 按钮函数中有一个设置状态,用于查看数组的新元素。
- 如何将新元素添加到数组中,同时将旧数据保留在文本字段中?
start_workout.dart
import 'package:flutter/material.dart';
import 'package:fultter_ultralifestyle/src/models/models.dart' show SetModel;
import 'package:fultter_ultralifestyle/src/presentation/widgets/dynamic_widget.dart';
class WorkoutStartScreen extends StatefulWidget {
static const String routeName = "workoutStart";
@override
_WorkoutStartScreenState createState() => _WorkoutStartScreenState();
}
class _WorkoutStartScreenState extends State<WorkoutStartScreen> {
final List<SetModel> sets = [
];
void _addSet() {
final id = sets.length;
sets.add(SetModel(id: id, pounds: 0, reps: 0));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout tracker"),
centerTitle: true,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: sets.length,
itemBuilder: (BuildContext context, int index) {
return DynamicWidget(
set: sets[index],
pos: index +1,
delete: () {
sets.removeAt(index);
setState(() {});
},
);
}),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addSet(),
child: Icon(Icons.add),
),
);
}
}
dynamic_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fultter_ultralifestyle/src/models/models.dart';
import 'package:fultter_ultralifestyle/src/presentation/widgets/text_widget.dart';
class DynamicWidget extends StatelessWidget {
final TextEditingController poundsController = TextEditingController();
final TextEditingController repsController = TextEditingController();
final SetModel set;
final int pos;
Function delete;
DynamicWidget({
Key key,
@required this.set,
@required this.pos,
@required this.delete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: text(
caption: "SET $pos",
),
),
SizedBox(width: 20.0),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: poundsController,
keyboardType: TextInputType.number,
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly,
],
),
SizedBox(height: 10),
text(caption: "pounds".toUpperCase()),
],
),
),
SizedBox(
width: 20,
),
text(caption: "X"),
SizedBox(
width: 20,
),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: repsController,
keyboardType: TextInputType.number,
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly
],
),
SizedBox(height: 10),
text(caption: "reps".toUpperCase()),
],
),
),
SizedBox(width: 5.0),
IconButton(
icon: Icon(Icons.delete_forever),
onPressed: delete,
)
],
),
],
),
);
}
}
使用控制器!
TextEditingController password = new TextEditingController();
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "Could not be empty";
}
return null;
},
enabled: !isLoading,
controller: password,
obscureText: hidePassword,
decoration: InputDecoration(
suffix: IconButton(icon: Icon((hidePassword)?Icons.remove_red_eye:Icons.cancel),onPressed: () => setState(() => hidePassword = !hidePassword),),
labelText: "PASSWORD",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20))),
onFieldSubmitted: (String p) {
buttonPressed();
},
),
然后使用
检索它
var pass = username.text;
显然您可以使用控制器数组然后检索它们
我通过在文本字段中的文本更改时更新 SetModel
来解决这个问题。主要部分是 updatePounds
和 updateReps
方法以及动态小部件中文本字段中的 onChanged
方法。
我还确保在构建动态小部件时使用 SetModel
中包含的值初始化控制器。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MaterialApp(
home: WorkoutStartScreen(),
));
}
class SetModel {
final int id;
int pounds;
int reps;
SetModel({
this.id,
this.pounds,
this.reps,
});
void updatePounds(int pounds) {
this.pounds = pounds;
}
void updateReps(int reps) {
this.reps = reps;
}
}
class WorkoutStartScreen extends StatefulWidget {
static const String routeName = "workoutStart";
@override
_WorkoutStartScreenState createState() => _WorkoutStartScreenState();
}
class _WorkoutStartScreenState extends State<WorkoutStartScreen> {
final List<SetModel> sets = [];
void _addSet() {
final id = sets.length;
setState(() {
sets.add(SetModel(id: id, pounds: 0, reps: 0));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout tracker"),
centerTitle: true,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: sets.length,
itemBuilder: (BuildContext context, int index) {
return DynamicWidget(
set: sets[index],
pos: index + 1,
delete: () {
setState(() {
sets.removeAt(index);
});
},
);
},
),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addSet(),
child: Icon(Icons.add),
),
);
}
}
class DynamicWidget extends StatelessWidget {
final TextEditingController poundsController = TextEditingController();
final TextEditingController repsController = TextEditingController();
final SetModel set;
final int pos;
final Function delete;
DynamicWidget({
Key key,
@required this.set,
@required this.pos,
@required this.delete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
if (set.pounds != 0) {
poundsController.text = set.pounds.toString();
}
if (set.reps != 0) {
repsController.text = set.reps.toString();
}
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Text(
"SET $pos",
),
),
SizedBox(width: 20.0),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: poundsController,
onChanged: (String pounds) {
set.updatePounds(int.parse(pounds));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("pounds".toUpperCase()),
],
),
),
SizedBox(
width: 20,
),
Text("X"),
SizedBox(
width: 20,
),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: repsController,
onChanged: (String reps) {
set.updateReps(int.parse(reps));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("reps".toUpperCase()),
],
),
),
SizedBox(width: 5.0),
IconButton(
icon: Icon(Icons.delete_forever),
onPressed: delete,
)
],
),
],
),
);
}
}
基本上,每次您从其父级调用 setState
时,都会重新绘制动态小部件。由于您从未告诉动态小部件保存任何内容,因此它们会从头开始重新绘制。这种情况仍在发生,只是现在我们给了他们一些初步信息。
Here 是它工作的视频。
我的技巧是让 TextField
具有属性 autofocus: true,
和 onChange(lock) => lock = true
然后当 initState 为 运行 或 widget 为 build 时,我们使用 if (lock == false)
setALLYourDataInController
设置数据
代码:
bool lock = false;
Widget build(BuildContext context) {
...
if (lock == false) {
firstNameController.text = detail?.firstName.toString() ?? '';
}
...
}
我的TextField
TextField(
autofocus: true,
style: kTextFieldTextStyle,
decoration: kInputDecoration.copyWith(
hintText: 'Yogithesymbian',
prefixIcon: Icon(Icons.person_add),
suffixIcon: firstNameController.text.isNotEmpty
? IconButton(
onPressed: firstNameController.clear,
icon: Icon(
Icons.clear,
color: kPrimaryColorLight,
),
)
: null,
),
onChanged: (unuse) {
lock = true; // here is logic
// set.updatePounds(int.parse(pounds));
},
textInputAction: TextInputAction.next,
controller: firstNameController,
),
- 我有一个文本字段数组。
- 向数组添加新文本字段的按钮。
- 如果您将数据添加到文本字段并通过单击添加按钮添加新元素,添加的数据将消失。
- 按钮函数中有一个设置状态,用于查看数组的新元素。
- 如何将新元素添加到数组中,同时将旧数据保留在文本字段中?
start_workout.dart
import 'package:flutter/material.dart';
import 'package:fultter_ultralifestyle/src/models/models.dart' show SetModel;
import 'package:fultter_ultralifestyle/src/presentation/widgets/dynamic_widget.dart';
class WorkoutStartScreen extends StatefulWidget {
static const String routeName = "workoutStart";
@override
_WorkoutStartScreenState createState() => _WorkoutStartScreenState();
}
class _WorkoutStartScreenState extends State<WorkoutStartScreen> {
final List<SetModel> sets = [
];
void _addSet() {
final id = sets.length;
sets.add(SetModel(id: id, pounds: 0, reps: 0));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout tracker"),
centerTitle: true,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: sets.length,
itemBuilder: (BuildContext context, int index) {
return DynamicWidget(
set: sets[index],
pos: index +1,
delete: () {
sets.removeAt(index);
setState(() {});
},
);
}),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addSet(),
child: Icon(Icons.add),
),
);
}
}
dynamic_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fultter_ultralifestyle/src/models/models.dart';
import 'package:fultter_ultralifestyle/src/presentation/widgets/text_widget.dart';
class DynamicWidget extends StatelessWidget {
final TextEditingController poundsController = TextEditingController();
final TextEditingController repsController = TextEditingController();
final SetModel set;
final int pos;
Function delete;
DynamicWidget({
Key key,
@required this.set,
@required this.pos,
@required this.delete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: text(
caption: "SET $pos",
),
),
SizedBox(width: 20.0),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: poundsController,
keyboardType: TextInputType.number,
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly,
],
),
SizedBox(height: 10),
text(caption: "pounds".toUpperCase()),
],
),
),
SizedBox(
width: 20,
),
text(caption: "X"),
SizedBox(
width: 20,
),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: repsController,
keyboardType: TextInputType.number,
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly
],
),
SizedBox(height: 10),
text(caption: "reps".toUpperCase()),
],
),
),
SizedBox(width: 5.0),
IconButton(
icon: Icon(Icons.delete_forever),
onPressed: delete,
)
],
),
],
),
);
}
}
使用控制器!
TextEditingController password = new TextEditingController();
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "Could not be empty";
}
return null;
},
enabled: !isLoading,
controller: password,
obscureText: hidePassword,
decoration: InputDecoration(
suffix: IconButton(icon: Icon((hidePassword)?Icons.remove_red_eye:Icons.cancel),onPressed: () => setState(() => hidePassword = !hidePassword),),
labelText: "PASSWORD",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20))),
onFieldSubmitted: (String p) {
buttonPressed();
},
),
然后使用
检索它var pass = username.text;
显然您可以使用控制器数组然后检索它们
我通过在文本字段中的文本更改时更新 SetModel
来解决这个问题。主要部分是 updatePounds
和 updateReps
方法以及动态小部件中文本字段中的 onChanged
方法。
我还确保在构建动态小部件时使用 SetModel
中包含的值初始化控制器。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MaterialApp(
home: WorkoutStartScreen(),
));
}
class SetModel {
final int id;
int pounds;
int reps;
SetModel({
this.id,
this.pounds,
this.reps,
});
void updatePounds(int pounds) {
this.pounds = pounds;
}
void updateReps(int reps) {
this.reps = reps;
}
}
class WorkoutStartScreen extends StatefulWidget {
static const String routeName = "workoutStart";
@override
_WorkoutStartScreenState createState() => _WorkoutStartScreenState();
}
class _WorkoutStartScreenState extends State<WorkoutStartScreen> {
final List<SetModel> sets = [];
void _addSet() {
final id = sets.length;
setState(() {
sets.add(SetModel(id: id, pounds: 0, reps: 0));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout tracker"),
centerTitle: true,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: sets.length,
itemBuilder: (BuildContext context, int index) {
return DynamicWidget(
set: sets[index],
pos: index + 1,
delete: () {
setState(() {
sets.removeAt(index);
});
},
);
},
),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addSet(),
child: Icon(Icons.add),
),
);
}
}
class DynamicWidget extends StatelessWidget {
final TextEditingController poundsController = TextEditingController();
final TextEditingController repsController = TextEditingController();
final SetModel set;
final int pos;
final Function delete;
DynamicWidget({
Key key,
@required this.set,
@required this.pos,
@required this.delete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
if (set.pounds != 0) {
poundsController.text = set.pounds.toString();
}
if (set.reps != 0) {
repsController.text = set.reps.toString();
}
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Text(
"SET $pos",
),
),
SizedBox(width: 20.0),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: poundsController,
onChanged: (String pounds) {
set.updatePounds(int.parse(pounds));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("pounds".toUpperCase()),
],
),
),
SizedBox(
width: 20,
),
Text("X"),
SizedBox(
width: 20,
),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: repsController,
onChanged: (String reps) {
set.updateReps(int.parse(reps));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("reps".toUpperCase()),
],
),
),
SizedBox(width: 5.0),
IconButton(
icon: Icon(Icons.delete_forever),
onPressed: delete,
)
],
),
],
),
);
}
}
基本上,每次您从其父级调用 setState
时,都会重新绘制动态小部件。由于您从未告诉动态小部件保存任何内容,因此它们会从头开始重新绘制。这种情况仍在发生,只是现在我们给了他们一些初步信息。
Here 是它工作的视频。
我的技巧是让 TextField
具有属性 autofocus: true,
和 onChange(lock) => lock = true
然后当 initState 为 运行 或 widget 为 build 时,我们使用 if (lock == false)
setALLYourDataInController
代码:
bool lock = false;
Widget build(BuildContext context) {
...
if (lock == false) {
firstNameController.text = detail?.firstName.toString() ?? '';
}
...
}
我的TextField
TextField(
autofocus: true,
style: kTextFieldTextStyle,
decoration: kInputDecoration.copyWith(
hintText: 'Yogithesymbian',
prefixIcon: Icon(Icons.person_add),
suffixIcon: firstNameController.text.isNotEmpty
? IconButton(
onPressed: firstNameController.clear,
icon: Icon(
Icons.clear,
color: kPrimaryColorLight,
),
)
: null,
),
onChanged: (unuse) {
lock = true; // here is logic
// set.updatePounds(int.parse(pounds));
},
textInputAction: TextInputAction.next,
controller: firstNameController,
),