【问题标题】:Flutter widget rebuilding when TextField widget clicked单击 TextField 小部件时 Flutter 小部件重建
【发布时间】:2019-08-23 18:24:34
【问题描述】:

我确定这是一个新手错误,但我似乎无法弄清楚这一点。 在下面的应用程序中,当单击第二条路由中的文本字段时,键盘会打开并立即关闭。经过仔细调查,似乎小部件在获得焦点时正在重建,导致路径重置,使用户无法输入文本。

当我从表单中删除“密钥”时,问题不会发生。这不是一个长期解决方案,因为我需要“密钥”以便验证表单。

有什么想法吗?

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

【问题讨论】:

  • 我在调试程序时遇到了类似的问题,在我的情况下,页面小部件是由 Navigator.push 触发的,并且似乎 Navigator.push 每次点击 TextField 时都会再次重新执行页面小部件创建.你试过在 Navigator.push 上设置断点吗?

标签: dart flutter


【解决方案1】:

如果您的屏幕依赖 MediaQuery至少在MediaQuery上有一个小部件,则键盘弹出窗口更改屏幕的大小,这会触发 mediaQuery 并导致重建...在这种情况下,请避免使用 mediaQuery,而是使用 (sizer package) https://pub.dev/packages/sizer

获取您的尺寸

【讨论】:

    【解决方案2】:

    当我们点击TextField 时,颤动会自动调用build() 方法,因此您的所有对象都会重新创建,并在build() 方法中进行初始化。

    这就是为什么总是创建在Form() 中使用的全局变量,例如:

    final emailController =  TextEditingController();
    final _formKey = GlobalKey<FormState>();
    

    【讨论】:

    • 您能否举例说明如何将全局变量_formKey 用于TextField
    【解决方案3】:

    当你点击 TextField 时,Flutter 会重新声明你的 _formKey。所以它会导致重建你的小部件。您需要在build 方法之外声明_formKey,这样Flutter 就不会重新声明您的变量。

    【讨论】:

      【解决方案4】:

      您必须在构建方法之外将 _formKey 声明为静态。

      【讨论】:

      • 感谢您的回复,在构建方法之外声明 _formkey 时也会发生同样的情况。
      • 使其成为静态的。
      • 谢谢你的工作!您能解释一下为什么将其声明为静态会有所不同吗?
      • 我对此了解不多。几天前我遇到了同样的问题,当时我在github的某个地方找到了解决方案。我认为 Flutter 尝试重新声明 formkey 并造成混乱,这就是为什么。
      猜你喜欢
      • 2020-06-23
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 2020-02-24
      • 2017-09-25
      • 2018-11-19
      相关资源
      最近更新 更多