StatefulWidget 页面在键盘打开时重新创建

Posted

技术标签:

【中文标题】StatefulWidget 页面在键盘打开时重新创建【英文标题】:StatefulWidget Page recreate when keyboard is open 【发布时间】:2019-05-24 00:19:33 【问题描述】:

在我的个人资料页面中有编辑选项,当使用单击编辑图标时,我使用布尔条件将 Text 小部件更改为 TextField 小部件,例如widget.isUpdate ? new Flexible(child: new TextField()) : Text("Text Widget") 它可以工作,但是当 TextField 聚焦时,键盘在那个时候打开 StatefulWidget 再次重新创建 Boolean变为 false 然后 Textfield 移动到 Text Widget。这种情况只发生在页面有导航器推送页面(第二页)之类的时候

 Navigator.push(context,MaterialPageRoute(builder: (context) => UpdateProfile()))

如果此页面作为默认主页,则可以正常工作。我不知道我犯了什么错误。

代码:

import 'package:flutter/material.dart';

class UpdateProfile extends StatefulWidget 
  bool isUpdate = false;

  @override
  State<StatefulWidget> createState() 
    // TODO: implement createState
    return UpdateProfileState();
  


class UpdateProfileState extends State<UpdateProfile> 
  @override
  Widget build(BuildContext context) 
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
          title: Text("Update"),
          elevation: 2.0),
      body: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.red,
        margin: const EdgeInsets.all(10.0),
        child: Row(
          children: <Widget>[
            widget.isUpdate ? new Flexible(child: new TextField()) : Text("Text Widget"),
            GestureDetector(
              child: IconTheme(
                  data: IconThemeData(color: Color(0xFFffffff)),
                  child: Icon(Icons.edit)),
              onTap: () 
                setState(() 
                  widget.isUpdate = !widget.isUpdate;
                );
              ,
            )
          ],
        ),
      ),
    );
  

问题:

如果我设置为主页,则可以正常工作,如下所示

import 'package:expense_manager_app/page/splash_page.dart';
import 'package:expense_manager_app/page/update_profile.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        brightness: Brightness.dark,
        primaryColor: Colors.red[500],
        accentColor: Colors.green[900],
      ),
      home: UpdateProfile(),
    );
  

【问题讨论】:

如果有人否决了这个问题,请说明原因 【参考方案1】:

您应该将变量 isUpdate 移动到您的状态中,记住小部件是不可变的。

        class UpdateProfileState extends State<UpdateProfile> 

         bool isUpdate = false;

          @override
          Widget build(BuildContext context) 
            // TODO: implement build
            return Scaffold(
              appBar: AppBar(
                  title: Text("Update"),
                  elevation: 2.0),
              body: Container(
                width: double.infinity,
                height: double.infinity,
                color: Colors.red,
                margin: const EdgeInsets.all(10.0),
                child: Row(
                  children: <Widget>[
                    isUpdate ? new Flexible(child: new TextField()) : Text("Text Widget"),
                    GestureDetector(
                      child: IconTheme(
                          data: IconThemeData(color: Color(0xFFffffff)),
                          child: Icon(Icons.edit)),
                      onTap: () 
                        setState(() 
                          isUpdate = !isUpdate;
                        );
                      ,
                    )
                  ],
                ),
              ),
            );
          
        

并且还要改变这个:

    Navigator.push(context,MaterialPageRoute(builder: (context) => UpdateProfile()))

到这里:

    final page = UpdateProfile();
    Navigator.push(context,MaterialPageRoute(builder: (context) => page ))

【讨论】:

是的,我已经厌倦了它的工作,但是为什么当这个页面像导航器推送一样作为第二页时它不能工作。它是如何作为主页默认页面工作的。 你有没有像我上面写的那样改变推送? 设置为 final 后它的工作所以我怀疑我是否直接在 MaterialPageRoute 中提到然后每次重新创建对象? 是的,构建器中的所有内容都已重新创建,因此您必须将小部件提取到变量中【参考方案2】:

这是因为你设置了默认 bool isUpdate = false; 将其更改为 bool isUpdate;

并使用 State 类的initState 方法并将isUpdate 设置为false。我会被叫一次。

@override
void initState()  
  widget.isUpdate = false;   
  super.initState();

【讨论】:

如果我在 initState 中设置的不是默认值,那么它会抛出错误 boolean expression must not be null @MageshPandian 然后将 bool isUpdate; 放入您的状态类中,然后删除 initState 方法中的 widget 前缀。 是的,它已经工作了,但我怀疑为什么它在键盘打开期间重新创建或重新初始化,当页面作为第二页而不是主页时【参考方案3】:

另外,如果你在 didChangeDependencies 方法上做一些事情,那也会导致

【讨论】:

以上是关于StatefulWidget 页面在键盘打开时重新创建的主要内容,如果未能解决你的问题,请参考以下文章

从 iPhone 主屏幕重新打开时,如何在 jQuery Mobile 应用程序上缓存并保留上次访问的页面?

ionic (webApp)软qv键盘打开时视口高度变小导致样式问题的解决方案

移动网络 - 如何在键盘打开时获取屏幕高度

应用打开时制作 Flutter alertdialog

键盘打开时如何固定小部件布局?

键盘打开时如何避免应用缩放?