Widget rebuild after TextField selection Flutter

15,186

Solution 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

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 3

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 4

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!

Share:
15,186
Nadox56
Author by

Nadox56

Updated on June 05, 2022

Comments

  • Nadox56
    Nadox56 almost 2 years

    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 !

  • boeledi
    boeledi almost 6 years
    Great work around but how would you deal when the build of the child uses a FutureBuilder ? thanks
  • iAkshay
    iAkshay over 4 years
    For me the issue was on android, iOS was working fine. (Might be iOS is handling the memory management well with ARC) The solution given here worked to get rid off the described issue on android. +10 :)
  • Daniel Silva
    Daniel Silva over 3 years
    I removed all unnecessary Keys/UniqueKeys and it worked, only removing the scaffoldKey didn't work for me, but it helped me test removing other ones, thanks for that!
  • RobbB
    RobbB over 2 years
    this property defaults to true