'Widget rebuild after TextField selection Flutter
I'm developping a Flutter App that needed to have a form. So when the user open the app, a Splash Screen appear before the form that have the following code :
import 'package:flutter/material.dart';
import '../model/User.dart';
import './FileManager.dart';
import './MyListPage.dart';
class UserLoader extends StatefulWidget {
@override
_UserLoaderState createState() => new _UserLoaderState();
}
class _UserLoaderState extends State<UserLoader> {
final userFileName = "user_infos.txt";
User _user;
@override
Widget build(BuildContext context) {
print("build UserLoader");
final _formKey = new GlobalKey<FormState>();
final _firstNameController = new TextEditingController();
final _lastNameController = new TextEditingController();
final _emailController = new TextEditingController();
final _phoneController = new TextEditingController();
return new Scaffold(
appBar: new AppBar(
title: new Text("Informations"),
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.save),
onPressed: () {
_user = _onFormValidate(
_formKey.currentState,
_firstNameController.text,
_lastNameController.text,
_emailController.text,
_phoneController.text);
})
],
),
body: new Center(
child: new SingleChildScrollView(
child: new Form(
key: _formKey,
child: new Column(children: <Widget>[
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: "Prénom",
),
keyboardType: TextInputType.text,
controller: _firstNameController,
validator: _validateName,
),
),
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: "Nom",
),
keyboardType: TextInputType.text,
controller: _lastNameController,
validator: _validateName,
),
),
Etc, etc ...
However when i tap the TextField, the keyboard appear and close immediately and all the component is rebuild. So it is impossible for me to complete the form..
Can someone have a solution please? Thanks in advance !
Solution 1:[1]
You haven't given us the entire code for this, so I don't know what the context is.
One pitfall I myself have fallen into (and might be affecting you, as I gather from your description) is having a stateful widget nested inside another stateful widget.
For instance,
class Parent extends StatefulWidget {
@override
ParentState createState() => ParentState();
(...)
}
class ParentState extends State<Parent> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Child(),
);
}
(...)
}
class Child extends StatefulWidget {
@override
ChildState createState() => ChildState();
(...)
}
class ChildState extends State<Child> {
@override
Widget build(BuildContext context) {
return TextField(...);
}
(...)
}
The problem here is that a rebuild of Parent means that ParentState().build()
is run, and a new Child
instance is created, with a new ChildState
object. Which resets everything.
Try not recreating ChildWidget, but instead saving it on ParentState, like so:
class Parent extends StatefulWidget {
@override
ParentState createState() => ParentState();
(...)
}
class ParentState extends State<Parent> {
Child _child;
@override
void initState() {
_child = Child();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _child,
);
}
(...)
}
// The rest remains the same
Edit: You just need to remember that, if your widget tree is a bit more complex, you may need to 1) pass a callback from the Parent to notify of state changes, and 2) not forget to also call setState() on the Child.
Solution 2:[2]
you just need make a new class and import that on your target class that seen problem. for example :
I usually create a class like this :
class MiddleWare
{
static MiddleWare shared = MiddleWare();
_MiddleWare(){}
String myText = "my Text";
// every variables should be here...
}
and
import "MiddleWare.dart";
class myclass extends StatefulWidget {
@override
_myclassState createState() => _myclassState();
}
class _myclassState extends State<myclass> {
@override
Widget build(BuildContext context) {
return Container(child: Text(MiddleWare.shared.myText));
}
}
that's it.
Solution 3:[3]
hi dont use Scaffold key i.e
Scaffold (
...
key: _scaffoldKey, //remove this
...
)
on the page and do a complete page rebuild (not hot reload), and you should be fine worked for me tho!
Solution 4:[4]
In my case, I have two stateful widgets, the parent and the child. I used the pushReplacement
method on the parent to fix the widget reload issue when the text form field is selected in the child widget.
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => WidgetChildren(idUser:
widget.idUser)),
);
Solution 5:[5]
try to create a function which receives context like this
class YourPage extends StatefulWidget {
const YourPage(Key key) : super(key: key);
static Future<void> show({ BuildContext context,}) async {
await Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
builder: (context) => YourPage()
);}
@override
_YourPageState createState() => _YourPageState();
}
......YourPage Build.....
then provide context to your page, when rebuilding it will have core context that prevents parent rebuild.
onPressed: () async {
await YourPage.show(context: context);
Solution 6:[6]
Move your variables (controllers and keys) from build
to class-fields level.
Solution 7:[7]
in my case it was related to this property in Scaffold widget: 'resizeToAvoidBottomInset'
I changed it to true and problem solved.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow