首页 > 解决方案 > 为什么 build() 在后台堆栈中的屏幕上被多次调用?

问题描述

我创建了一个类似于Navigate to a new screen and back示例的示例项目。我在每个屏幕上的唯一TextField区别autofocus: 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,
          )
        ],
      ),
    );
  }
}

当我导航ThirdScreenFourthScreen我的日志时,如下所示:

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. 为什么后台的屏幕在键盘弹出时会被reguild?
  3. 为什么 FirstScreen 没有被重建?

标签: flutterflutter-layout

解决方案


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

  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() 中将 rout/screen 名称分配给提供者

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

推荐阅读