我的 Flutter 应用程序中有以下
StatefulWidget
:
class EditProfilePage extends StatefulWidget {
const EditProfilePage({super.key});
@override
State<EditProfilePage> createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
ProfileClient client = ProfileClient();
TextEditingController usernameController = TextEditingController();
Future<ProfileResponse>? futureProfileResponse;
@override
void initState() {
super.initState();
futureProfileResponse = fetch();
}
Future<ProfileResponse> fetch() async {
String key = await Utils.getKey();
return client.get(key);
}
@override
void dispose() {
usernameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Edit profile'),
),
body: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height),
child: buildPage())));
}
FutureBuilder<ProfileResponse> buildPage() {
return FutureBuilder<ProfileResponse>(
future: futureProfileResponse,
builder: (context, snapshot) {
if (snapshot.hasData) {
ProfileResponse profileResponse = snapshot.data!;
if (profileResponse.code == 200) {
usernameController.text = profileResponse.profile.username;
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
TextField(
controller: usernameController,
decoration: const InputDecoration(
labelText: 'Username',
),
),
],
),
);
}
}
return const Center(child: CircularProgressIndicator());
});
}
}
我不明白为什么,在用户名里面写
TextField
,然后按后退按钮,TextField
的内容又回到之前的值。
准确地说,当我用
buildPage()
小部件包装 ConstrainedBox
方法时,这个问题就开始出现。我这样做是因为在我的原始页面中我有更多 TextField
小部件,我需要它们在打开键盘时“向上移动”。为了简单起见,我删除了与这个特定问题无关的部分代码。
当用户打开/关闭键盘时,可用的屏幕尺寸将发生变化,这使得小部件重建。整个
FutureBuilder
将被重建,并且 builder
将执行将文本分配给控制器的行。您可以通过在其前面添加打印语句来验证:
print('Widget rebuild at ${DateTime.now()}');
usernameController.text = profileResponse.profile.username;
使用
FutureBuilder
的原因是仅在 future 完成后渲染 TextField
,否则渲染 CircularProgressIndicator
。设置控制器的值应该与这个小部件构建机制分开。您可以在 text
方法中设置控制器的 fetch
值:
Future<ProfileResponse> fetch() async {
String key = await Utils.getKey();
final profileResponse = client.get(key);
usernameController.text = profileResponse.profile.username;
return profileResponse;
}
在
FutureBuilder
中,删除此行:
usernameController.text = profileResponse.profile.username;
这样,当小部件重建时,
usernameController.text
赋值线就不会被调用。