【问题标题】:Why build() is being called multiple times on screens in the backstack?为什么 build() 在后台堆栈中的屏幕上被多次调用?
【发布时间】:2019-06-08 16:34:11
【问题描述】:

我创建了一个类似于Navigate to a new screen and back 示例的示例项目。我在每个屏幕上都有TextFieldautofocus: true 的唯一区别:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Navigation Basics',
    home: FirstScreen(),
  ));
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("FirstScreen build");
    return Scaffold(
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('Next screen'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => SecondScreen()),
              );
            },
          ),
          TextField(
            decoration: InputDecoration(),
            onEditingComplete: () {},
            autofocus: true,
          )
        ],
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("SecondScreen build");
    return Scaffold(
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('Next screen'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => ThirdScreen()),
              );
            },
          ),
          TextField(
            decoration: InputDecoration(),
            onEditingComplete: () {},
            autofocus: true,
          )
        ],
      ),
    );
  }
}

class ThirdScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("ThirdScreen build");
    return Scaffold(
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('Next screen'),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => FourthScreen()),
              );
            },
          ),
          TextField(
            decoration: InputDecoration(),
            onEditingComplete: () {},
            autofocus: true,
          )
        ],
      ),
    );
  }
}

class FourthScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("FourthScreen build");
    return Scaffold(
      body: Column(
        children: <Widget>[
          TextField(
            decoration: InputDecoration(),
            onEditingComplete: () {},
            autofocus: true,
          )
        ],
      ),
    );
  }
}

当我从 ThirdScreen 导航到 FourthScreen 时,我的日志如下所示:

I/flutter ( 7523): FourthScreen build
I/flutter ( 7523): SecondScreen build
I/flutter ( 7523): ThirdScreen build
I/flutter ( 7523): FourthScreen build
I/flutter ( 7523): SecondScreen build
I/flutter ( 7523): ThirdScreen build
I/flutter ( 7523): FourthScreen build
  1. 为什么在第一次构建 FourthScreen 之后 SecondScreen,ThirdScreen 和 FourthScreen build 又被调用?
  2. 为什么 backstack 中的屏幕在键盘弹出时会被重新排列?
  3. 为什么不重建 FirstScreen?

【问题讨论】:

标签: flutter flutter-layout


【解决方案1】:

我尝试运行您提供的重现,但无法复制您报告的问题。导航到下一个屏幕后不会重建以前的屏幕。

颤抖的医生

[✓] Flutter (Channel stable, 1.22.3, on Mac OS X 10.15.7 19H2, locale en)
    • Flutter version 1.22.3
    • Framework revision 8874f21e79 (5 days ago), 2020-10-29 14:14:35 -0700
    • Engine revision a1440ca392
    • Dart version 2.10.3

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.0.1, Build version 12A7300
    • CocoaPods version 1.9.0

[!] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.50.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.15.1

[✓] Connected device (2 available)
    • AOSP on IA Emulator (mobile) • emulator-5554                        • android-x86 • Android 9 (API 28) (emulator)
    • iPhone 11 (mobile)           • 216904B4-E876-4AC5-9BCF-F77CD19B9338 • ios         • com.apple.CoreSimulator.SimRuntime.iOS-14-0 (simulator)

如果您仍然遇到问题,请提供最小限度的重现以及复制行为的步骤并将其归档在此处http://github.com/flutter/flutter/issues/

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我使用以下方法解决了这个问题。

    1. 使用提供者获取当前页面。
    2. 创建String类型route的变量(route为变量名)
    3. 在每个屏幕上调用提供商并分配该屏幕名称。
    4. 在屏幕、菜单抽屉或您正在导航的任何地方呼叫提供商。

    提供者类代码

      class RouteProvider with ChangeNotifier {
      String _route = "initial";
    
      String get route => _route;
      set route(String data) {
        this._route = data;
        notifyListeners();
      }
    }
    

    在 build() 中将路由/屏幕名称分配给提供程序

     final route = context.watch<RouteProvider>().route = "OffersView";
    

    在构建内部的消费者屏幕上

     final route = context.watch<RouteProvider>().route;
      if (route != "OffersView") {
                          Navigator.pushAndRemoveUntil(
                              context,
                              MaterialPageRoute(
                                  builder: (Context) => OffersPage()),
                              (route) => false);
                        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 2010-12-15
      • 2017-05-08
      相关资源
      最近更新 更多