Flutter:如何在来回切换屏幕后将列表数据保留在 table 内?
Flutter: How to keep list data inside table even after switching screens back and forth?
我有一个用于 CRUD 的表单(第二个屏幕)。当我添加数据时,它会保存到列表视图中,如您在 table.
中所见
列表视图被传递到(第一个屏幕),我可以在其中迭代并查看具有更新内容的列表数据。
但是,当我点击转到第二个屏幕时,列表视图数据消失了。出于测试目的,给定的 3 个列表是硬编码的。
现在,我的问题是,即使多次来回切换屏幕,我怎样才能将数据保存在 table 中而不消失。我的代码如下:-
**
- Main.dart 文件
**
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _userInformation = 'No information yet';
void languageInformation() async {
final language = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
updateLanguageInformation(language);
}
void updateLanguageInformation(List<User> userList) {
for (var i = 0; i <= userList.length; i++) {
for (var name in userList) {
print("Name: " + name.name[i] + " Email: " + name.email[i]);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(_userInformation),
],
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
languageInformation();
},
child: Text("Go to Form"),
),
],
),
);
}
}
2。 Model.dart 文件:
class User {
String name;
String email;
User({this.name, this.email});
}
3。第 5 集文件
class Episode5 extends StatefulWidget {
@override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
bool update = false;
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
@override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: userList
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
currentIndex = userList.indexOf(user);
_updateTextControllers(user); // new function here
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
bodyData(),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
Navigator.pop(context, userList);
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
void updateForm() {
setState(() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
});
}
void _updateTextControllers(User user) {
setState(() {
nameController.text = user.name;
emailController.text = user.email;
});
}
void addUserToList(name, email) {
setState(() {
userList.add(User(name: name, email: email));
});
}
}
因此与其在页面之间来回传递数据,不如实施状态管理解决方案,这样您就可以从应用程序中的任何位置访问您的数据,而无需手动传递任何内容。
可以使用任何状态管理解决方案来完成,这里是您可以使用 GetX 来完成的方法。
我把你所有的变量和方法都放在了 Getx class 中。此 class 中的任何内容都可以从应用程序的任何位置访问。我摆脱了 setState
因为这不再是更新的方式。
class FormController extends GetxController {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
void updateForm() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
update();
}
void updateTextControllers(User user) {
nameController.text = user.name;
emailController.text = user.email;
update();
}
void addUserToList(name, email) {
userList.add(User(name: name, email: email));
update();
}
void updateLanguageInformation() {
// for (var i = 0; i <= userList.length; i++) { // ** don't need nested for loop here **
for (var user in userList) {
print("Name: " + user.name + " Email: " + user.email);
}
// }
}
}
GetX 控制器可以在您尝试使用它之前在任何地方进行初始化,但让我们主要进行初始化。
void main() {
Get.put(FormController()); // controller init
runApp(MyApp());
}
这是您的页面,我们找到了控制器,现在所有变量和方法都来自该控制器。
class Episode5 extends StatefulWidget {
@override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
// finding same instance if initialized controller
final controller = Get.find<FormController>();
@override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: controller.userList // accessing list from Getx controller
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
controller.currentIndex =
controller.userList.indexOf(user);
controller.updateTextControllers(user);
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
// GetBuilder rebuilds when update() is called
GetBuilder<FormController>(
builder: (controller) => bodyData(),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: controller.nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: controller.emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
controller.addUserToList(
controller.nameController.text,
controller.emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
controller.updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
controller.updateLanguageInformation(); // all this function does is print the list
Navigator.pop(
context); // don't need to pass anything here
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
}
这是您的另一页。为了演示目的,我只是将 ListView.builder
包裹在 GetBuilder<FormController>
中。它现在可以是无状态的。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Expanded(
child: GetBuilder<FormController>(
builder: (controller) => ListView.builder(
itemCount: controller.userList.length,
itemBuilder: (context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(controller.userList[index].name),
Text(controller.userList[index].email),
],
),
),
),
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
},
child: Text("Go to Form"),
),
],
),
);
}
}
随着您的应用扩展,您可以创建更多控制器 class,而且它们都可以从任何地方轻松访问。与到处手动传递数据相比,这是一种更简单、更简洁的做事方式。
我有一个用于 CRUD 的表单(第二个屏幕)。当我添加数据时,它会保存到列表视图中,如您在 table.
中所见列表视图被传递到(第一个屏幕),我可以在其中迭代并查看具有更新内容的列表数据。
但是,当我点击转到第二个屏幕时,列表视图数据消失了。出于测试目的,给定的 3 个列表是硬编码的。
现在,我的问题是,即使多次来回切换屏幕,我怎样才能将数据保存在 table 中而不消失。我的代码如下:-
**
- Main.dart 文件
**
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _userInformation = 'No information yet';
void languageInformation() async {
final language = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
updateLanguageInformation(language);
}
void updateLanguageInformation(List<User> userList) {
for (var i = 0; i <= userList.length; i++) {
for (var name in userList) {
print("Name: " + name.name[i] + " Email: " + name.email[i]);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(_userInformation),
],
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
languageInformation();
},
child: Text("Go to Form"),
),
],
),
);
}
}
2。 Model.dart 文件:
class User {
String name;
String email;
User({this.name, this.email});
}
3。第 5 集文件
class Episode5 extends StatefulWidget {
@override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
bool update = false;
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
@override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: userList
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
currentIndex = userList.indexOf(user);
_updateTextControllers(user); // new function here
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
bodyData(),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
Navigator.pop(context, userList);
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
void updateForm() {
setState(() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
});
}
void _updateTextControllers(User user) {
setState(() {
nameController.text = user.name;
emailController.text = user.email;
});
}
void addUserToList(name, email) {
setState(() {
userList.add(User(name: name, email: email));
});
}
}
因此与其在页面之间来回传递数据,不如实施状态管理解决方案,这样您就可以从应用程序中的任何位置访问您的数据,而无需手动传递任何内容。
可以使用任何状态管理解决方案来完成,这里是您可以使用 GetX 来完成的方法。
我把你所有的变量和方法都放在了 Getx class 中。此 class 中的任何内容都可以从应用程序的任何位置访问。我摆脱了 setState
因为这不再是更新的方式。
class FormController extends GetxController {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
void updateForm() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
update();
}
void updateTextControllers(User user) {
nameController.text = user.name;
emailController.text = user.email;
update();
}
void addUserToList(name, email) {
userList.add(User(name: name, email: email));
update();
}
void updateLanguageInformation() {
// for (var i = 0; i <= userList.length; i++) { // ** don't need nested for loop here **
for (var user in userList) {
print("Name: " + user.name + " Email: " + user.email);
}
// }
}
}
GetX 控制器可以在您尝试使用它之前在任何地方进行初始化,但让我们主要进行初始化。
void main() {
Get.put(FormController()); // controller init
runApp(MyApp());
}
这是您的页面,我们找到了控制器,现在所有变量和方法都来自该控制器。
class Episode5 extends StatefulWidget {
@override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
// finding same instance if initialized controller
final controller = Get.find<FormController>();
@override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: controller.userList // accessing list from Getx controller
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
controller.currentIndex =
controller.userList.indexOf(user);
controller.updateTextControllers(user);
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
// GetBuilder rebuilds when update() is called
GetBuilder<FormController>(
builder: (controller) => bodyData(),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: controller.nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: controller.emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
controller.addUserToList(
controller.nameController.text,
controller.emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
controller.updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
controller.updateLanguageInformation(); // all this function does is print the list
Navigator.pop(
context); // don't need to pass anything here
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
}
这是您的另一页。为了演示目的,我只是将 ListView.builder
包裹在 GetBuilder<FormController>
中。它现在可以是无状态的。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Expanded(
child: GetBuilder<FormController>(
builder: (controller) => ListView.builder(
itemCount: controller.userList.length,
itemBuilder: (context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(controller.userList[index].name),
Text(controller.userList[index].email),
],
),
),
),
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
},
child: Text("Go to Form"),
),
],
),
);
}
}
随着您的应用扩展,您可以创建更多控制器 class,而且它们都可以从任何地方轻松访问。与到处手动传递数据相比,这是一种更简单、更简洁的做事方式。