Flutter应用程序中每个页面的多个支架

问题描述 投票:1回答:2

API文档:https://api.flutter.dev/flutter/material/Scaffold-class.html说:

[脚手架被设计为用于MaterialApp,通常不需要嵌套支架。对于选项卡式UI中的示例,其中bottomNavigationBar是TabBar,主体是一个TabBarView,您可能很想制作每个选项卡栏查看带有不同标题的AppBar的脚手架。会更好向用于更新AppBar的TabController添加侦听器。

是否意味着在Material App下仅需要一个单一的Scaffold,或者每个页面只有一个单一的父Scaffold。如果是第一个,我们如何导航?如果是稍后的版本,这是否意味着在每次导航时都重新渲染通用的AppBarBottomBar?最佳做法是什么。

android flutter navigation material-design scaffolding
2个回答
1
投票

这通常意味着每一页(更准确地说,每个Scaffold /屏幕)应该有一个Route,并且您不应该嵌套Scaffold

在屏幕之间导航

例如,查看可以在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!'),
        ),
      ),
    );
  }
}

在这里,您可以看到有两个不同的页面/Routes /屏幕,每个页面都有自己的Scaffold。我们使用Navigator来回导航,因此我们的页面被添加到堆栈中,其中一个Scaffold位于另一个页面的顶部。很好。

如果是稍后的版本,是否不意味着在每个导航上都重新渲染通用的AppBar和BottomBar?

是,但这正是我们制作两个单独的屏幕,每个屏幕都有自己的Scaffold时想要的。

在支架内部导航/嵌套导航

另一方面,看这个例子:

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: () {},
          ),
        ),
      ),
    );
  }
}

[这里,我们嵌套两个Scaffold,并且如您所见,第二个应用程序栏被绘制在第一个应用程序栏的下方。对于选项卡式导航或嵌套式导航,这不是最佳方法。如果要在Scaffold的正文中导航并根据内容更改应用栏,则首选使用TabControllers,例如DefaultTabController。看一下这个例子:

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

如您所见,我们只使用了一个Scaffold,因为我们实际上只处理一个屏幕。碰巧我们想要显示内容页面并在Scaffold的正文中导航。

结论

作为一般的经验法则:每个Scaffold /屏幕仅使用一个Route。仅将一个Scaffold与诸如TabControllerIndexedStack之类的小部件一起使用才能浏览单个屏幕主体内的内容。


0
投票

我建议您为应用程序使用ScaffoldAppBar共同的BottomBar,并且当用户更改BottomBar选项卡时,您必须管理Scaffold的主体。

您可以使用多个标签来管理单个脚手架:

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;
    });
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.