【问题标题】:Widget rebuild after TextField selection FlutterTextField 选择 Flutter 后的小部件重建
【发布时间】:2018-05-11 15:37:05
【问题描述】:

我正在开发一个需要有表单的 Flutter 应用程序。因此,当用户打开应用程序时,在表单前会出现一个启动画面,其中包含以下代码:

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 ...

但是,当我点击 TextField 时,键盘会立即出现并关闭,并且所有组件都会重新构建。所以我不可能完成表格..

请问有人可以解决吗?提前致谢!

【问题讨论】:

标签: forms dart textfield flutter


【解决方案1】:

你还没有给我们完整的代码,所以我不知道上下文是什么。

我自己陷入的一个陷阱(并且可能会影响到你,正如我从你的描述中得知的那样)是有一个有状态的小部件嵌套在另一个有状态的小部件中。

例如,

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(...);
  }

  (...)
}

这里的问题是,Parent 的重建意味着 ParentState().build() 正在运行,并创建了一个 new Child 实例,并带有一个新的 ChildState 对象。这会重置一切。

尝试不重新创建 ChildWidget,而是将其保存在 ParentState 中,如下所示:

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

编辑:您只需要记住,如果您的小部件树有点复杂,您可能需要 1)从父级传递回调以通知状态更改,以及 2)不要忘记也调用 ​​setState( ) 在孩子身上。

【讨论】:

  • 很好的解决方法,但是当孩子的构建使用 FutureBuilder 时,您将如何处理?谢谢
  • 对我来说,问题出在 android 上,iOS 运行良好。 (可能是 iOS 使用 ARC 很好地处理了内存管理)这里给出的解决方案可以摆脱在 android 上描述的问题。 +10 :)
【解决方案2】:

您只需要创建一个新类并将其导入您发现问题的目标类。例如:

我通常这样创建一个类:

class MiddleWare
{
  static MiddleWare shared = MiddleWare();
  _MiddleWare(){}
  String myText = "my Text";
  // every variables should be here...
}

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));
  }
}

就是这样。

【讨论】:

    【解决方案3】:

    你好,不要使用脚手架键,即

        Scaffold (
        ...
        key: _scaffoldKey, //remove this
        ...
        )
    

    在页面上并进行完整的页面重建(不是热重载),你应该为我工作!

    【讨论】:

    • 我删除了所有不必要的 Keys/UniqueKeys 并且它起作用了,只是删除了脚手架Key 对我不起作用,但它帮助我测试了删除其他的,谢谢!
    【解决方案4】:

    就我而言,我有两个有状态的小部件,父级和子级。我在父级上使用了pushReplacement 方法来修复在子小部件中选择文本表单字段时的小部件重新加载问题。

    Navigator.pushReplacement(
       context,
       MaterialPageRoute(builder: (context) => WidgetChildren(idUser: 
       widget.idUser)),
    );
    

    【讨论】:

      【解决方案5】:

      尝试创建一个接收这样的上下文的函数

      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.....
      

      然后为您的页面提供上下文,在重建时它将具有阻止父级重建的核心上下文。

      onPressed: () async {
                   await YourPage.show(context: context);
      

      【讨论】:

        【解决方案6】:

        在我的例子中,它与 Scaffold 小部件中的这个属性有关:'resizeToAvoidBottomInset'

        我将其更改为 true 并解决了问题。

        【讨论】:

        • 此属性默认为true
        猜你喜欢
        • 2019-08-23
        • 1970-01-01
        • 2020-06-23
        • 2021-07-15
        • 2020-02-24
        • 2022-01-21
        • 1970-01-01
        • 2020-07-25
        • 2020-12-22
        相关资源
        最近更新 更多