如何让BottomNavigationBar通过AlertDialog响应导航到新页面?

时间:2019-07-17 15:41:20

标签: flutter dart navigation bottomnavigationview

我有一个navigation_bar.dart文件,该文件可以处理我的应用程序中的新页面更改。在其中,我使用bottomNavigationBar根据当前选择的选项卡来构建四个不同的页面,如下所示:

class NavigationBar extends StatefulWidget {
  @override
  _NavigationBarState createState() => _NavigationBarState();
}

class _NavigationBarState extends State<NavigationBar> {
  int _selectedIndex = 0;
  final List<Widget> _pageOptions = <Widget>[
    Page1(),
    Page2(),
    Page3(),
    Page4(),
  ];

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

  @override
  Widget build(BuildContext context) {
    String userID =
        Provider.of<FirebaseUser>(context, listen: false) != null ? Provider.of<FirebaseUser>(context).uid : 'null';

    return MultiProvider(
      providers: [StreamProvider<MyUser>.value(value: DatabaseService().streamUser(userID))],
      child: Scaffold(
        body: IndexedStack(
          children: _pageOptions,
          index: _selectedIndex,
        ),
        bottomNavigationBar: Theme(
          data: Theme.of(context).copyWith(
            canvasColor: Color(0xff271037).withOpacity(0.90),
            splashColor: Colors.transparent,
          ),
          child: BottomNavigationBar(
            currentIndex: _selectedIndex,
            onTap: _onItemTapped,
            unselectedItemColor: Colors.white,
            selectedItemColor: Color(0xff3ADEA7),
            type: BottomNavigationBarType.fixed,
            items: <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Container(),
                title: Icon(FontAwesomeIcons.fire, color: Colors.white),
              ),
              BottomNavigationBarItem(
                icon: Container(),
                title: Icon(Icons.fastfood, color: Colors.white),
              ),
              BottomNavigationBarItem(
                icon: Container(),
                title: Icon(Icons.directions_bike, color: Colors.white),
              ),
              BottomNavigationBarItem(
                icon: Container(),
                title: Icon(Icons.person, color: Colors.white),
              )
            ],
          ),
        ),
      ),
    );
  }
}

现在,在该页面的另一个Page3.dart文件中,弹出一个警告对话框,单击该对话框时,我希望它导航到Page4()。

Future<void> _showMissingDataDialog(String data) async {
    return showDialog<void>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('You have not set your $data yet.'),
          actions: <Widget>[
            FlatButton(
              splashColor: Colors.transparent,
              highlightColor: Colors.grey[200],
              textColor: Colors.black,
              child: const Text('Cancel'),
              onPressed: () => Navigator.of(context).pop(),
            ),
            FlatButton(
                splashColor: Colors.transparent,
                highlightColor: Colors.grey[200],
                textColor: Colors.black,
                child: Text('Set $data', style: TextStyle(fontWeight: FontWeight.bold)),
                onPressed: () {
                  Navigator.of(context).pop();
                  // TODO: Redirect to page4() here as if it was tapped on the BottomNavigationBar
                })
          ],
        );
      },
    );
  }

我如何拥有它,以便单击“设置$ data”按钮将路由到Page4()?我希望这样做,以便bottomNavigationBar对此做出反应,就像您点击实际的第四个BottomNavigationBarItem项一样。

2 个答案:

答案 0 :(得分:0)

我能够通过使用IndexedStack并创建一个Provider类来解决此问题,该类具有从任何其他类更改_currentpage的值的功能。

class NavigationBar extends StatefulWidget {
  @override
  _NavigationBarState createState() => _NavigationBarState();
}

class _NavigationBarState extends State<NavigationBar> {
  int _selectedIndex = 0;
  final List<Widget> _pageOptions = <Widget>[
    Page1(),
    Page2(),
    Page3(),
    Page4(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
      Provider.of<NavBarProvider>(context).currentPage = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    String userID =
        Provider.of<FirebaseUser>(context, listen: false) != null ? Provider.of<FirebaseUser>(context).uid : 'null';

    return MultiProvider(
      providers: [StreamProvider<MyUser>.value(value: DatabaseService().streamUser(userID))],
      child: Scaffold(
        body: IndexedStack(
          children: _pageOptions,
          index: Provider.of<NavBarProvider>(context).currentPage,
        ),
        bottomNavigationBar: BottomNavBar(),
      ),
    );
  }
}

class BottomNavBar extends StatefulWidget {
  BottomNavBar({Key key}) : super(key: key);

  _BottomNavBarState createState() => _BottomNavBarState();
}

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

  @override
  void initState() {
    _selectedIndex = Provider.of<NavBarProvider>(context, listen: false).currentPage;

    super.initState();
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
      Provider.of<NavBarProvider>(context, listen: false).currentPage = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        canvasColor: const Color(0xff271037),
        splashColor: Colors.transparent,
      ),
      child: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        unselectedItemColor: Colors.white,
        selectedItemColor: const Color(0xff3ADEA7),
        type: BottomNavigationBarType.fixed,
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Container(),
            title: const Icon(FontAwesomeIcons.fire, color: Colors.white),
          ),
          BottomNavigationBarItem(
            icon: Container(),
            title: const Icon(Icons.fastfood, color: Colors.white),
          ),
          BottomNavigationBarItem(
            icon: Container(),
            title: const Icon(Icons.directions_bike, color: Colors.white),
          ),
          BottomNavigationBarItem(
            icon: Container(),
            title: const Icon(Icons.person, color: Colors.white),
          )
        ],
      ),
    );
  }
}

这是Provider类:

import 'package:flutter/foundation.dart';

class NavBarProvider extends ChangeNotifier {
  int _currentPage = 0;

  set currentPage(int pageInt) {
    _currentPage = pageInt;
    notifyListeners();
  }

  int get currentPage => _currentPage;
}

然后可以通过导入提供程序类并按如下方式更改页面来更改页面:

Provider.of<NavBarProvider>(context).currentpage = 3;

不幸的是,这并不完美,因为它没有为onTapped模拟BottomNavigationBarItem。通常,当您单击具有我所拥有代码的图标时,该图标会产生动画效果,使其尺寸增大,而使用此解决方案时不会发生这种情况。只会更改加载的页面。

答案 1 :(得分:0)

为导航栏提供全局密钥。我在主Dart文件的所有小部件之外声明了这一点。

GlobalKey navBarGlobalKey = GlobalKey(debugLabel: 'bottomAppBar');

bottomNavigationBar: BottomNavigationBar(
        key: navBarGlobalKey,
        onTap: _onItemTapped,
        currentIndex: _selectedIndex,
        type: BottomNavigationBarType.fixed,
        items: [ ... ]

然后使用全局键在按钮的onPressed方法中调用onTap方法。您必须先将另一个dart文件导入此页面,然后才能使用全局密钥。

final BottomNavigationBar navigationBar = navBarGlobalKey.currentWidget;
              initialIndex = 0;
              navigationBar.onTap(3); //Starts at index 0, so passing in 3 should do the trick.