Flutter:保留 BottomNavigationBar 并根据 BottomNavigationBar 的选定索引将用户路由到正确的屏幕

Flutter: Persist BottomNavigationBar and route user to the correct screen depending on the selected index of the BottomNavigationBar

我希望 BottomNavigationBar 持续存在,并根据用户选择的索引以及 BottomNavigationBar 上突出显示的索引将用户发送到不同的屏幕。

我尝试这样做的方法是根据 BottomNavigationBar() 当前选择的索引更改 Scaffold 的正文值。一旦选择了 BottomNavigationBar() 的选定索引,我就可以突出显示它,但是正文没有路由到适当的小部件。

BottomNavBaronTap: 引用的当前方法正确突出显示了选定的索引,但没有路由到正确的小部件。

我的 BottomNavBar 中有一个未使用的方法 (_switchScreen)。将此作为 BottomNavBar()onTap: 的值适当地路由到正确的屏幕,但随后我必须在每个视图上重建 BottomNavBar 并且在 BottomNavBar 后面无法访问在 NavModel(导航模型)中引用。

这是我的 BottomNavBar():

import 'package:flutter/material.dart';

import '../screens/Add_Media_Screen.dart';
import '../screens/Profile_Screen.dart';
import '../screens/Venture_Feed_Screen.dart';
   
class BottomNavBar extends StatefulWidget {
  @override
  _BottomNavBarState createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  void _switchScreen(index) {
    switch (index) {
      case 0:
        Navigator.pushNamed(context, VentureFeedScreen.routeName);
        break;
      case 1:
        Navigator.pushNamed(context, ProfileScreen.routeName);
        break;
      case 2:
        Navigator.pushNamed(context, AddMediaScreen.routeName);
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(
        primaryColor: Color(0xff84d1da),
        accentColor: Color(0xff62c2a2),
      ),
      child: BottomNavigationBar(
        selectedItemColor: Color(0xff84d1da),
        unselectedItemColor: Colors.grey,
        type: BottomNavigationBarType.fixed,
        items: const <BottomNavigationBarItem>[
          //Index 0
          BottomNavigationBarItem(
            icon: Icon(
              Icons.explore,
            ),
            label: 'Discover',
          ),
          //Index 1
          BottomNavigationBarItem(
            icon: Icon(
              Icons.account_circle,
              // color: Color(0xff84d1da),
            ),
            label: 'Profile',
            // backgroundColor: Color(0xff84d1da),
          ),
          //Index 2
          BottomNavigationBarItem(
            icon: Icon(
              Icons.add_circle_outline,
            ),
            label: 'Add Media',
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
      ),
    );
  }
}

这里是 NavModel:

import 'package:flutter/material.dart';

import '../screens/Profile_Screen.dart';
import '../screens/Venture_Feed_Screen.dart';
import '../screens/Add_Media_Screen.dart';

import '../widgets/BottomNavBar.dart';

class NavModel extends StatefulWidget {
  static const routeName = '/nav-model';
  @override
  _NavModelState createState() => _NavModelState();
}

class _NavModelState extends State<NavModel> {
  int _currentIndex = 0;

  final tabs = [
    VentureFeedScreen(),
    ProfileScreen(),
    AddMediaScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: tabs[_currentIndex],
        bottomNavigationBar: BottomNavBar(),
      ),
    );
  }
}

我认为您想要完成的是 PageView class 的行为,对吗?将 PageView 作为脚手架的主体,并将 tabs 作为子项传递给 PageView。

将其拆分为两个不同的 classes 在这种情况下不起作用。在 NavModel() class body: 属性 的 Scaffold 中,我试图根据 tabs 列表更新值_currentIndex 的静态索引值为 0。我认为通过调用 BottomNavBar() class 并将 onTap: 值设置为根据 _onItemTapped 进行更新方法,它将根据 BottomNavBar class 中 _onItemTapped 方法中定义的内容更新 body: 值。这是不正确的。

代码 运行 与我定义的一样正确:脚手架的 body: tabs[_currentIndex] 正在调用正确的逻辑 - 在选项卡列表的 0 索引处显示该项目。当发生这种情况时,BottomNavBar 的索引正在更新以反映正确的用户选择的索引和值,从而导致混淆为什么 BottomNavBar 选择的索引正在更新而 Scaffold 的主体保持不变。

正确代码如下:

class BottomNavBar extends StatefulWidget {
  static const routeName = '/navigator-model';
  @override
  _BottomNavBarState createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  final List<Widget> tabs = [
    VentureFeedScreen(),
    ProfileScreen(),
    AddMediaScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: tabs.elementAt(_selectedIndex),
      bottomNavigationBar: BottomNavigationBar(
        selectedItemColor: Color(0xff84d1da),
        unselectedItemColor: Colors.grey,
        type: BottomNavigationBarType.fixed,
        items: const <BottomNavigationBarItem>[
          //Index 0
          BottomNavigationBarItem(
            icon: Icon(
              Icons.explore,
            ),
            label: 'Discover',
          ),
          //Index 1
          BottomNavigationBarItem(
            icon: Icon(
              Icons.account_circle,
              // color: Color(0xff84d1da),
            ),
            label: 'Profile',
            // backgroundColor: Color(0xff84d1da),
          ),
          //Index 2
          BottomNavigationBarItem(
            icon: Icon(
              Icons.add_circle_outline,
            ),
            label: 'Add Media',
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
      ),
    );
  }
}

但是,我还没有看到 BottomNavBar 是否继续导航到另一个屏幕(尚未构建该功能)。