I have the following StatefulWidget
in my Flutter application:
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());
});
}
}
I dont' understand the reason why, writing inside the username TextField
and then pressing the back button, the content of the TextField
comes back to the previous value.
This is a demo to make better understand my problem: Demo GIF
To be precise, this problem started to appear as soon as I wrapped the buildPage()
method with a ConstrainedBox
widget. I did so because in my original page I had more TextField
widgets and I needed them to "move up" when opening the keyboard. For the sake of simplicity, I removed parts of the code that were not related to this specific problem.
When the user opens/closes the keyboard, the available screen size will change, which makes the widget rebuilds. The entire
FutureBuilder
will be rebuilt and thebuilder
will execute the line where you assign the text to the controller. You can verify by adding a print statement right before it:The reason you use
FutureBuilder
is to renderTextField
only after the future completes and renderCircularProgressIndicator
otherwise. Setting the value for the controller should be separated from this widget building mechanism. You can set thetext
value for the controller in thefetch
method:In the
FutureBuilder
, remove this line:This way, the
usernameController.text
assignment line won't be called when the widget rebuilds.