【发布时间】:2021-07-01 09:00:42
【问题描述】:
我目前正在学习 Flutter 并取得了不错的进步,所以如果这是一个菜鸟问题,请多多包涵。
在我的应用程序中,我创建了一个页面以允许登录用户修改他们的个人资料。在这个页面中,我有一个 TextFormField(用于编辑电子邮件)和一个 ToggleButtons(有两个选项)来选择一个职业。
我使用 FutureBuilder 从数据库中检索我的数据,以便使用电子邮件预填充 TextFormField。我也有用户的职业。这些部分运行良好。
但是现在,当我尝试我的应用程序并按下(onPressed 事件)切换按钮来更改职业时,我的行为很糟糕。在 onPressed 事件中,我使用 setState() 来刷新小部件,以便每次更改专业时都从数据库中预先填充电子邮件字段。
我想知道如何处理这个案子?这样做的最佳做法是什么? 因为我需要这些值来提交表单。 我尝试拆分小部件以隔离切换按钮,但无法将所选值发送到父小部件。
谢谢!
编辑:添加代码
这是我的个人资料页面的代码:
class MyProfilePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return MyProfilePageState();
}
}
class MyProfilePageState extends State<MyProfilePage> {
final FirebaseAuth auth = FirebaseAuth.instance;
final StudentService StudentService = new StudentService();
final TeacherService TeacherService = new TeacherService();
final _formKey = GlobalKey<FormState>();
Teacher _teacher;
Student _student;
User user;
String uid;
TextEditingController emailController = TextEditingController();
@override
void initState() {
user = auth.currentUser;
super.initState();
}
Future<bool> isProfileRetrieved() async {
_student = await StudentService.getByUid(user.uid);
_teacher = await TeacherService.getTeacherByUid(user.uid);
fillFields();
return true;
}
void fillFields() {
emailController.text = _teacher == null ? _student.email : _teacher.email;
}
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(primaryColor: primaryColor),
child: Scaffold(
appBar: AppBar(
title: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Image.asset(
'assets/logo.png',
fit: BoxFit.contain,
height: 45,
),
Container(
padding: const EdgeInsets.all(8.0),
child: Text('Teacher Monitoring')),
Image.asset(
'assets/logo.png',
fit: BoxFit.contain,
height: 45,
),
]),
backgroundColor: Colors.black,
),
body: FutureBuilder(
future: isProfileRetrieved(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
return Container(child: Form(
key: _formKey,
child: Column(children: <Widget>[
emailField(),
ProfessionWidget(),
saveButton()
])));
} else {
return CircularProgressIndicator();
}
},)),
);
}
Widget emailField() {
return TextFormField(
controller: emailController,
decoration: const InputDecoration(
hintText: 'Enter your email',
prefixIcon: Icon(Icons.person),
labelText: "Email"),
validator: (String value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
);
}
Widget saveButton() {
return SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
icon: Icon(Icons.save_alt),
label: Text("Save"),
style: ElevatedButton.styleFrom(
primary: primaryColor, // background
onPrimary: Colors.white, // foreground
),
onPressed: () {
if (_formKey.currentState.validate()) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Update Profile')));
}
},
),
);
}
}
这就是隔离 ToggleButton 的代码(这是我最后一次尝试解决我的问题):
class ProfessionWidget extends StatefulWidget {
Teacher teacher;
Student student;
@override
_ProfessionWidgetState createState() => _ProfessionWidgetState(teacher, student);
}
class _ProfessionWidgetState extends State<ProfessionWidget> {
Teacher teacher;
Student student;
List<bool> isSelected;
_ProfessionWidgetState(Teacher teacher, Student student);
@override
void initState() {
super.initState();
isSelected = [true, false];
}
@override
Widget build(BuildContext context) {
return professionField();
}
Future<bool> isProfileRetrieved(teacher, student) async {
isSelected = [teacher != null, student != null];
return true;
}
Widget professionField() {
return Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 7.0),
child: Text('Profession',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold))),
ToggleButtons(
borderColor: Colors.grey,
selectedColor: Colors.white,
fillColor: primaryColor,
borderRadius: BorderRadius.circular(10),
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0, left: 20.0),
child: Text(
'Teacher',
style: TextStyle(fontSize: 16),
),
),
Padding(
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0, left: 20.0),
child: Text(
'Student',
style: TextStyle(fontSize: 16),
),
),
],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0;
buttonIndex < isSelected.length;
buttonIndex++) {
isSelected[buttonIndex] = buttonIndex == index;
if (buttonIndex == index) {
//TODO
}
}
});
},
isSelected: isSelected,
)
]));
}
}
【问题讨论】:
-
您可以编辑您的问题并显示您的代码吗?这将使人们更容易以这种方式看到并帮助您。
-
你是对的,我添加了代码:)
-
解决此问题的最佳方法是创建扩展
FormField的自定义小部件。这样做将允许您在顶层拥有一个Form,并在层次结构中拥有多个有状态的小部件。看看这篇文章:blog.bam.tech/developer-news/…,或者这个复选框的答案:stackoverflow.com/questions/53479942/checkbox-form-validation