Multiple Scaffolds for each page inside a Flutter App

此生再无相见时 提交于 2020-07-09 07:39:40

问题


The API documentation: https://api.flutter.dev/flutter/material/Scaffold-class.html says:

The Scaffold was designed to be the single top level container for a MaterialApp and it's typically not necessary to nest scaffolds. For example in a tabbed UI, where the bottomNavigationBar is a TabBar and the body is a TabBarView, you might be tempted to make each tab bar view a scaffold with a differently titled AppBar. It would be better to add a listener to the TabController that updates the AppBar.

Does it mean there needs to be only one single Scaffold under the Material App or one single parent Scaffold for each page. If it's the first, how do we navigate? If the it's later, doesn't it mean the common AppBar and BottomBar get re-rendered on each navigation? What's the best practice.


回答1:


It means that, usually, there should be one Scaffold for each page (more precisely, for each Route/screen), and that you should not nest Scaffolds.

Navigating between screens

For example, take a look at this snippet that you can run in DartPad:

import 'package:flutter/material.dart';

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

class FirstRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Route'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Open route'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondRoute()),
            );
          },
        ),
      ),
    );
  }
}

class SecondRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Route"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go back!'),
        ),
      ),
    );
  }
}

Here, you can see there are two distinct pages/Routes/screens, and each one has its own Scaffold. We are navigating back and forth by using Navigator, and so our pages are being added to the stack, one Scaffold on top of the other. That is fine.

If the it's later, doesn't it mean the common AppBar and BottomBar get re-rendered on each navigation?

Yes, but that is precisely what we want when we make two separate screens, each one with its own Scaffold.

Navigating inside the body of a Scaffold / nested navigations

On the other hand, take a look at this example:

import 'package:flutter/material.dart';

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

class FirstRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Route'),
      ),
      body: Scaffold(
        body: Center(
          child: RaisedButton(
            child: Text('Open route'),
            onPressed: () {},
          ),
        ),
      ),
    );
  }
}

Here, we are nesting two Scaffolds, and, as you can see, the second app bar is being drawn below the first app bar. That would not be the best approach for tabbed or nested navigations. If you want to navigate inside the body of a Scaffold, and change the app bar depending on the content, using TabControllers, such as DefaultTabController, is preferred. Take a look at this example:

import 'package:flutter/material.dart';

void main() {
  runApp(TabBarDemo());
}

class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: [
                Tab(icon: Icon(Icons.directions_car)),
                Tab(icon: Icon(Icons.directions_transit)),
                Tab(icon: Icon(Icons.directions_bike)),
              ],
            ),
            title: Text('Tabs Demo'),
          ),
          body: TabBarView(
            children: [
              Icon(Icons.directions_car),
              Icon(Icons.directions_transit),
              Icon(Icons.directions_bike),
            ],
          ),
        ),
      ),
    );
  }
}

As you can see, we have used only one Scaffold, since we are dealing with only one screen, really. It just happens that we want to show content pages and navigate inside the body of the Scaffold.

Conclusion

As a general rule of thumb: use only one Scaffold per Route/screen. Use only one Scaffold with widgets such as TabController or IndexedStack to navigate the content inside the body of a single screen.




回答2:


I am suggesting you use common Scaffold with AppBar and BottomBar for your application and as the user change the BottomBar tabs you have to manage the body of the Scaffold.

You can manage your single Scaffold with multiple tabs like this:

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  int _currentIndex;
  List<Widget> _children;

  @override
  void initState() {
    _currentIndex = 0;
    _children = [
      Screen1(),
      Screen2(),
      Screen3(),
      Screen4(),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _children[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: onTabTapped,
        type: BottomNavigationBarType.fixed,
        fixedColor: Colors.blue,
        items: [
          BottomNavigationBarItem(
            title: Text("Screen 1"),
          ),
          BottomNavigationBarItem(
            title: Text("Screen 2"),
          ),
          BottomNavigationBarItem(title: Text("Screen 3")),
          BottomNavigationBarItem(title: Text("Screen 4")),
        ],
      ),
    );
  }

  void onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }
}


来源:https://stackoverflow.com/questions/60561552/multiple-scaffolds-for-each-page-inside-a-flutter-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!