Flutter跨页面改变BottomNavigationBar选中下标

前言

需求是这样的,bottomBar内有A,B,C,D页面,4个页面由tabBar管理显示,当在A页面点击按钮时让TabBar选中B页面展示,通俗来讲就是在两个不相邻的Widget里,一个Widget改变另一个Widget的状态。

思路:

解决方案1:

flutter内有Provider的状态管理,可以定义一个全局的Provider ,在Main函数内装载,放入顶层结构中,全局访问Provider改变Provider的状态,以此来更新Widget的状态显示

解决方案2:

使用event_bus 发送事件广播 ,A页面发送广播,tabBar监听广播并改变下标

下面是代码部分

方案1(Provider方案) 代码:

1.编写Provider类

//方案1 使用provider 跨页面改变tabBar选中的下标
class RootProvider extends ChangeNotifier {

  int index = 0;

  void changeIndex(int newIndex){
    index = newIndex;
    print("change");
    notifyListeners();
  }

}
  1. main函数注入编写好的Provider
  runApp(
    MultiProvider(
        providers: [
            // 注入全局顶层Provider
            ChangeNotifierProvider(create: (_) => RootProvider()),
        ],
      child: MyApp(),

    )
  );
  1. tabBar监听Provider改变index
     //方案1  使用provider跨页面改变tabBar的index
    @override
  Widget build(BuildContext context) {
    print("tabbar build");
    return Consumer(
      builder: (_,__,___){
        // 获取更改的下标
        int currentIndex = Provider.of(context, listen: false).index;

        return Scaffold(
          bottomNavigationBar: BottomNavigationBar(
            items: _buildItemList(),
            type: BottomNavigationBarType.fixed,
            currentIndex: currentIndex,
            iconSize: 21.0,
            elevation: 5.0,
            selectedFontSize: 12,
            unselectedFontSize: 12,
            selectedItemColor: Color.fromRGBO(42, 130, 253, 1),
            unselectedItemColor: Color.fromRGBO(142, 142, 147, 1),
            onTap: (index){
              // 点击方法内改变下标重新刷新
              Provider.of(context,listen: false).changeIndex(index);
            },
          ) ,
// 叠加布局,选中的index在最上面
          body: IndexedStack(
            index: currentIndex,
            children: _pageList,
          ),
        );
      },
    );
}

4.在A页面调用这个Provider 使tabBar改变选中下标

// 如A页面的点击函数内
GestureDetector(
                onTap: () {
                    // 调用Provider选中第1个 即第2个页面(ps: 下标从0开始的哦~)
                    Provider.of(context,listen: false).changeIndex(1);
                }

下面看一下方案2 使用event_bus发送事件广播的方式

方案2(event_bus方案) 代码:

1.编写消息对象,也就是想要发送的消息内容

import 'package:event_bus/event_bus.dart';
//Bus 初始化
EventBus eventBus = EventBus();


// tabBar切换选中页面
class EventTabBarIndex{
// 参数为int 即需要改变的下标
  int index;
  EventTabBarIndex(this.index);
}

2.在BottomNavigationBar所属的widget文件内监听通知 , 此Widget应是一个有状态的Widget


class _TabBarPageState extends State with RestorationMixin  {

  RootProvider provider = RootProvider();



  @override
// init监听 
  void initState() {
    // TODO: implement initState
    super.initState();
    eventBus.on().listen((event) {
      provider.value = event.index;
      _pageController.jumpToPage(event.index);
    });
  }

  @override
  Widget build(BuildContext context) {

  return ChangeNotifierProvider(
      create: (_) => provider,
     child:Scaffold(
        bottomNavigationBar: Consumer(
          builder:(_,provider,__){
            return  BottomNavigationBar(
              items: _buildItemList(),
              type: BottomNavigationBarType.fixed,
              currentIndex: provider.value,
              iconSize: 21.0,
              elevation: 5.0,
              selectedFontSize: 12,
              unselectedFontSize: 12,
              selectedItemColor: Color.fromRGBO(42, 130, 253, 1),
              unselectedItemColor: Color.fromRGBO(142, 142, 147, 1),
              onTap: (index) {
                _pageController.jumpToPage(index);
              } ,
            );
          },
        ),
        body: PageView(
          physics: const NeverScrollableScrollPhysics(), // 禁止滑动
          controller: _pageController,
        onPageChanged: (int index) => provider.value = index,
          children: _pageList,
        ),
      )
    );
}

// 状态保活
@override
  // TODO: implement restorationId
  String? get restorationId => "root";

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    registerForRestoration(provider, "tabBarCurrentIndex");
  }

}

3.状态保活的Provider ,这里的Provider与方案1的Provider是不相等的

class RootProvider extends RestorableInt{
  RootProvider():super(0);
}

总结

  1. 方案1 Provider注入全局,使整个全局都有了一个Provider可以在任何地方访问它,读取数据 。
  2. 方案2 使用event_bus发送事件与监听事件的方式,向事件总线中添加了一个事件,需要定义发送的消息内容,同时发送者发送数据,监听者监听事件作出相应。
可依据自我情况合理选择实现方案

你可能感兴趣的:(Flutter跨页面改变BottomNavigationBar选中下标)