flutter TextField选择抖动后的小部件重建

8e2ybdfx  于 2023-04-22  发布在  Flutter
关注(0)|答案(8)|浏览(187)

我正在开发一个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 ...

然而,当我点击文本字段,键盘出现并立即关闭,所有的组件都被重建。所以我不可能完成的形式。
有没有人能给我一个解决方案?谢谢!

mftmpeh8

mftmpeh81#

你还没有给我们完整的代码,所以我不知道上下文是什么。
我自己曾经陷入过的一个陷阱(从您的描述中可以看出,这可能会影响到您)是将一个有状态的小部件嵌套在另一个有状态的小部件中。
比如说

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()运行,并创建了一个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)从Parent传递一个回调来通知状态更改,2)不要忘记在Child上调用setState()。

gjmwrych

gjmwrych2#

你只需要创建一个新的类,并将其导入到你的目标类中。例如:
我通常会创建一个这样的类:

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

就是这样。

rpppsulh

rpppsulh3#

嗨,不要使用脚手架钥匙

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

在页面上做一个完整的页面重建(而不是热重载),你应该为我工作的好tho!

dzjeubhm

dzjeubhm4#

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

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

ef1yzkbh5#

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

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);
6vl6ewon

6vl6ewon6#

将变量(控制器和键)从build移动到类字段级别。

kb5ga3dv

kb5ga3dv7#

formkey应该是final的,并且在build方法之外

pgccezyw

pgccezyw8#

在我的例子中,它与Scaffold小部件中的这个属性相关:'resizeToAvoidBottomInset'
我把它改成真的,问题就解决了。

相关问题