在Navigator.push之后专注于目标页面上的文本字段时,将再次调用Navigator.push

时间:2019-02-21 08:13:14

标签: flutter

发生以下现象。

  1. FirstPageNextPageNavigation.push的过渡。
  2. TextField中选择NextPage
  3. 1被再次调用。
  4. 使用键盘完成。
  5. 1被再次调用。

以下是来源。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("sample"),
      ),
      body: RaisedButton(
        onPressed: () {
          Navigator.of(context).push(
            MaterialPageRoute(builder: (context) {
              print("Before call NextPage()");
              return NextPage();
            }),
          );
        },
        child: Text("next page"),
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("next page"),
      ),
      body: TextField(),
    );
  }
}

下面是gif动画,点击“文本字段”和“完成”键盘时,将在其中打印日志。

enter image description here

为什么会这样? (bug?)
我该怎么解决?

2 个答案:

答案 0 :(得分:0)

如您所见,即使多次调用该日志,您也只会在第一个日志上看到过渡,或者换句话说,您将获得所需的效果。这是有原因的。让我们分解一下:

使用Flutter,由于多种原因,builders可以被多次调用,并且应该是幂等的(不影响逻辑业务);

也就是说,当您导航到第二个屏幕时,您正在构建TextFormField,它是 Stateless Widget `的子元素,该元素应该是不变的。这意味着应该在构造函数中传递其最终值(如果需要),并且每次状态更改时(例如,字段的默认文本)都将需要更改,从而通过触发生成器来重建视图;

因此,例如,如果您改用 Stateful Widget ,那么您的构建器将不会被调用,而仅会调用其 State <的build方法/ em>。

您可以在类似的已解决问题here

中找到有关此问题的讨论

答案 1 :(得分:0)

我遇到了同样的问题,解决方法是:

  1. 创建一个全局变量,例如gstrCurPage ='First'

  2. 在主窗口小部件中,不要仅返回firstpage(),而是添加一个'switch'语句,根据gstrCurPage返回firstpage()或nextpage()。

  3. 在首页的单击按钮中,设置gstrCurPage ='Next'

要允许将“许多页面”存储在“许多Dart文件”中,请首先创建一个名为“ GlobalVariables.dart”的Dart文件,并将所有“全局变量”存储在此文件中。

class gv {
    // Declare Global Variables Here to be accessed by all 'Pages'
    // These variables must be static !!!
    static String gstrCurPage = 'First';
}

以下是您原始程序的更新:

import 'package:flutter/material.dart';
import 'GlobalVariables.dart';

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

class MyApp extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    switch (gv.gstrCurPage) {
        case 'First':
            return MaterialApp(
                home: FirstPage(),
            );
            break;
        case 'Next':
            return MaterialApp(
                home: NextPage(),
            );
            break;
        default:
            return MaterialApp(
                home: FirstPage(),
            );
    }
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("sample"),
      ),
      body: RaisedButton(
        onPressed: () {
          Navigator.of(context).push(
            MaterialPageRoute(builder: (context) {
              print("Before call NextPage()");
              gv.gstrCurPage = 'Next';
              return NextPage();
            }),
          );
        },
        child: Text("next page"),
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("next page"),
      ),
      body: TextField(),
    );
  }
}

现在,您可以将“首页”和“下一页”(以及其他页面)放在单独的dart文件中,所有这些文件都应导入“ GlobalVariables.dart”。所有页面“知道”类gv中定义的变量的任何更改。