如何使用底部导航栏从脚手架主体内部推送路线?

Posted

技术标签:

【中文标题】如何使用底部导航栏从脚手架主体内部推送路线?【英文标题】:How to push a Route from inside the body of a scaffold with a bottomnavigationbar? 【发布时间】:2021-09-22 07:51:23 【问题描述】:

我的 main.dart 在 Nav() 小部件内有一个 MaterialApp,它包含一个带有 appBar 和 BottomNavigationBar 的 Scaffold。 NavigationBar 有 4 个 BottomNavigationBarItems,但我的整个应用程序中的页面数超过了 4 个。其他页面可以通过第一个 BottomNavigationBarItem 'Home' 访问。但是当我推送新的 NamedRoute 时,AppBar 消失了。我该如何解决这个问题?

我已经尝试在我自己的小部件中的新文件中使用底部导航栏。问题:setState() 不起作用。

这里有一些代码

main.dart:

import 'package:flutter/material.dart';
import 'pages/nav.dart';
import 'route/route.dart' as route;

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Lieferantenapp',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.red,
      ),
      home: Nav(),
      onGenerateRoute: route.controller,
      //initialRoute: route.navPage,
    );
  

nav.dart

import 'package:flutter/material.dart';
import 'package:lieferantenapp/components/MyAppBar.dart';
import 'package:lieferantenapp/components/MyThreeLineText.dart';
//import 'package:lieferantenapp/components/myBottomNavigationBar.dart';
import 'package:lieferantenapp/components/myCard.dart';
import 'package:lieferantenapp/pages/bestellungen.dart';
import 'package:lieferantenapp/pages/packliste.dart';
import 'package:lieferantenapp/pages/tour.dart';
import 'package:lieferantenapp/pages/home.dart';

class Nav extends StatefulWidget 
  @override
  _NavState createState() => _NavState();


class _NavState extends State<Nav> 
  int _selectedIndex = 0;
  List<Widget> _widgetOptions = <Widget>[
    Home(),
    Tour(),
    Bestellungen(),
    Packliste(),
  ];

  void _onItemTap(int index) 
    setState(() 
      _selectedIndex = index;
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      //Custom App Bar without any passed data
      appBar: myAppBar(context, null, null),
      backgroundColor: Colors.white,
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        type: BottomNavigationBarType.fixed,
        fixedColor: Colors.red,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(
            icon: Icon(Icons.local_shipping),
            label: 'Tour',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.inventory_2),
            label: 'Packliste',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.receipt_long),
            label: 'Bestellungen',
          ),
        ],
        onTap: _onItemTap,
      ),
      body: _widgetOptions.elementAt(_selectedIndex),
    );
  

home.dart:

import 'package:flutter/material.dart';
import 'package:lieferantenapp/components/MyThreeLineText.dart';
import 'package:lieferantenapp/components/myCard.dart';

class Home extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Column(
      children: [
        //BlackBoard Message
        //TODO get BlackBoard Message from Server
        //myThreeLineText(Context, TextTheme, OVerline, Title, Body)
        myThreeLineText(
          context,
          Theme.of(context).textTheme,
          '12.07.2021',
          'Servus und Mahlzeit!',
          "Herzlich Willkommen in der neuen Mahlzeit LieferApp mit " +
              "optimierter Routenplanung via Google Maps.",
        ),
        Expanded(
          child: GridView.count(
            shrinkWrap: true,
            primary: false,
            padding: const EdgeInsets.all(18),
            crossAxisSpacing: 15,
            mainAxisSpacing: 15,
            crossAxisCount: 2,
            children: <Widget>[
              myCard(
                context,
                Icons.map_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xff119052),
              ),
              myCard(
                context,
                Icons.local_shipping_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xffFF9444),
              ),
              myCard(
                context,
                Icons.inventory_2_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xff84000F),
              ),
              myCard(
                context,
                Icons.receipt_long_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xffCB5E5E),
              ),
              myCard(
                context,
                Icons.bookmark_border_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xffCC3021),
              ),
              myCard(
                context,
                Icons.settings_outlined,
                'Touren',
                Theme.of(context).textTheme,
                Color(0xff57BB61),
              ),
            ],
          ),
        ),
      ],
    );
  

myCard.dart:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:lieferantenapp/route/route.dart' as route;

Widget myCard(BuildContext context, IconData icon, String text, TextTheme theme,
    Color cColor) 
  return GestureDetector(
    //TODO implement ROUTE ontap start Cards
    onTap: () => ,
    child: Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(30),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            icon,
            color: Colors.white,
            size: 30,
          ),
          SizedBox(height: 25),
          Text(
            text,
            style: theme.bodyText1.apply(color: Colors.white),
          ),
        ],
      ),
      color: cColor,
    ),
  );

我也愿意接受提示和技巧来改进我的代码。

编辑 - 新 main.dart:

import 'package:flutter/material.dart';
import 'package:lieferantenapp/components/MyAppBar.dart';

import 'pages/nav.dart';
import 'route/route.dart' as route;

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Mahlzeit Lieferantenapp',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      //home: Nav(),
      //onGenerateRoute: route.controller,
      builder: (context, _) => Scaffold(
        appBar: myAppBar(context, null, null),
        body: Navigator(onGenerateRoute: route.controller),
      ),
      //initialRoute: route.navPage,
    );
  

【问题讨论】:

【参考方案1】:

应用栏是 Scaffold 的一部分,它只会出现在 _widgetOptions 中的 4 个小部件上。如果您的页面上没有该 Scaffold,则没有应用栏。

用脚手架(即导航器顶部的脚手架)包裹导航器应该可以解决问题。

请注意,当您从构建函数“返回”一个小部件时,它会变成一个子部件。当您使用 Navigator 推送一个 Widget 时,它会成为一个兄弟,并将位于当前屏幕的顶部。您可以在开发工具中清楚地看到这一点。

编辑:由于您使用的是默认 MaterialApp 的导航器,这将不起作用。您需要为此创建自己的导航器。

即:从 MaterialApp 中删除 home 参数。请改用 builder 参数。并为构建器提供一个 Navigator 小部件(由您的 Scaffold 包装)

类似这样的:

MaterialApp(builder: (context, _) => Scaffold(....., body: Navigator(onGenerateRoutes:...)))

【讨论】:

感谢您的快速回答!我收到上面发布的新 main.dart 的以下错误:A HeroController can not be shared by multiple Navigators. The Navigators that share the same HeroController are: 错误在“是:”之后结束 编辑:忘记了初始路由 - 修复了错误 收到另一个错误:The following _CompileTimeError was thrown building Builder(dirty): Unimplemented handling of missing static target The relevant error-causing widget was MaterialApp 你知道如何解决吗?或者你知道另一种解决方法吗? 我相信热重启或停止并重新运行应用程序应该可以修复该错误。 如果我的回答有帮助,请接受并点赞

以上是关于如何使用底部导航栏从脚手架主体内部推送路线?的主要内容,如果未能解决你的问题,请参考以下文章

将底部导航栏的代码与脚手架分离

将值传递给要在底部工作表中使用的浮动操作按钮

底部导航栏的 onItemSelectedListener

颤动底部导航,其中一页有标签

颤动底部导航,其中一个页面有选项卡

为啥我的底部导航栏在推送时变为空白?