'Flutter widget rebuilding when TextField widget clicked
I'm sure this is a rookie error however I can't seem to figure this one out. In the app below, when the textfield in the second route is clicked the keyboard opens and immediately closes. On closer investigation it seems that the widget is being rebuilt whenever it gets focus, causing the route to reset, making it impossible for the user to enter text.
When I remove the "key" from the form the problem doesn't occur. This isn't a long term fix as I need the "key" so I can validate the form.
Any ideas?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My app',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.lightBlue,
fontFamily: 'Nunito',
),
home: LoginPage(),
);
}
}
class LoginPage extends StatefulWidget {
@override
LoginPageState createState() {
return new LoginPageState();
}
}
class LoginPageState extends State<LoginPage> {
Widget build(BuildContext context) {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final registerButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
child: Text('Register Now', style: TextStyle(color: Colors.white)),
),
);
// Now load the main login page
return Scaffold(
backgroundColor: Colors.white,
key: _scaffoldKey,
body: Center(
child: ListView(
shrinkWrap: true,
children: <Widget>[
registerButton,
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final emailController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
controller: emailController,
autofocus: false,
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Center(
child: Form(
key: _formKey,
child: email,
),
),
);
}
}
Solution 1:[1]
you have to declare _formKey as static outside of build method.
Solution 2:[2]
if your screen depends on MediaQuery or at least having one widget depenig on MediaQuery, the keyboard popup changes the size of your screen, which triggers mediaQuery and causing rebuilds...in this case avoid using mediaQuery, Instead get your dimensions using (sizer package) https://pub.dev/packages/sizer
Solution 3:[3]
When we click on TextField then build() method is called automatically by flutter so your all object is recreate which initialise within build() method.
That's why always create global variable which is used in Form() like :
final emailController = TextEditingController();
final _formKey = GlobalKey<FormState>();
Solution 4:[4]
When you click to TextField, Flutter redeclare your _formKey. So it cause to rebuild your widget. You need to declare _formKey outside the build method so Flutter will not redeclare your variable.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Viren V Varasadiya |
| Solution 2 | Ahmed Salah |
| Solution 3 | Sanjayrajsinh |
| Solution 4 | t13n |
