以编程方式更改 BottomNavigationBar 上的选项卡而不使用 BottomNavigationBar 的 onTap?

Change tab on BottomNavigationBar Flutter programmatically and without using onTap of BottomNavigationBar?

我正在开发一个 flutter 应用程序,当用户从其余 BottomNavigationBar 屏幕的任何其他屏幕按下时,我需要重定向到 BottomNavigationBar 上的第一个屏幕。现在,我在一个简单的按钮上添加了重定向事件,将在 _onWillPop 事件上替换它。

请找到下面的代码:

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {

  final PageStorageBucket bucket = PageStorageBucket();

  Widget currentScreen = HomeFragment();
  int currentTab = 0;

  static int selectedIndexN = 0;
  static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  List<Widget> _widgetOptions1 = <Widget>[
    HomeFragment(),
    LoginFargment(),
    SignUpFargment(),
    ProfileFargment(),
  ];

  void changeTabMethod(int index) {
    print('changeTabMethod is called');
    setState(() {
      selectedIndexN = index;
    });
    print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // return GetBuilder<DashboardController>(
      body: Center(
        child: _widgetOptions1.elementAt(selectedIndexN),
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: selectedIndexN,
        onTap: changeTabMethod,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Login',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'SignUp',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}

个人资料屏幕代码:

class ProfileFargment extends StatefulWidget {
  @override
  _ProfileFragmentState createState() => _ProfileFragmentState();
}

class _ProfileFragmentState extends State<ProfileFargment> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:SafeArea(
          child: Container(
            padding: EdgeInsets.all(20.0),
            height: double.infinity,
            width: double.infinity,
            color: Colors.teal,
            child: GestureDetector(
                  onTap: () {
                    //Calling method changeTabMethod(0)
                    HomeScreen().createState().changeTabMethod(0);
                  },
                  child: Container(
                    margin: EdgeInsets.only(top: 20.0),
                    height: 40.0,
                    width: 150.0,
                    color: Colors.white,
                    child: Center(child: Text('Profile'),),
                  ),
                ),
        ),
      ),
    );
  }
}

另一方面,当我从 ProfileFragment 屏幕调用 changeTabMethod 时,它将进入 changeTabMethod 但无法执行 setState 方法。所以我的标签没有改变。

您可以考虑这个控制台报告: changeTabMethod is called 仅在 setState 未执行后第二次打印。

你能告诉我哪里做错了什么吗?

提前致谢:-)

这其实很简单,你只需要将功能传递给子部件即可。

因此您的 ProfileFragment 将采用类型为 Function(int) 的名为 changeTab 的变量:

Function(int) changeTab;
ProfileFragment(this.changeType); // Constructor

当您在 _HomeScreenState:

中创建小部件时,您会忽略它
List<Widget> _widgetOptions1 = <Widget>[
  …
  ProfileFargment(changeTabMethod),
];

然后就可以直接在_ProfileFragmentState中调用函数了:

onTap: () => widget.changeTab(0);

试试下面的代码。通过将函数作为参数传递,您可以从任何其他页面触发主页上的函数。 主屏幕代码:

 class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      final PageStorageBucket bucket = PageStorageBucket();
    
    //       Widget currentScreen = HomeFragment();
      int currentTab = 0;
    
      static int selectedIndexN = 0;
      static const TextStyle optionStyle =
          TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
    
      Widget _widgetOptions1(int index) {
        switch (index) {
          case 0:
            return ProfileFargment(onButtonPressed: changeTabMethod);
    
          case 1:
            return Container(child: Text("Page - 2 "));
    
          case 2:
            return Container(child: Text("Page - 3 "));
          default:
            return Container();
        }
      }
    
      void changeTabMethod(int index) {
        print('changeTabMethod is called');
        setState(() {
          selectedIndexN = index;
        });
        print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          // return GetBuilder<DashboardController>(
          body: Center(
            child: _widgetOptions1(selectedIndexN),
          ),
          bottomNavigationBar: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            currentIndex: selectedIndexN,
            onTap: changeTabMethod,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                label: 'Home',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.business),
                label: 'Login',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.school),
                label: 'SignUp',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.school),
                label: 'Profile',
              ),
            ],
          ),
        );
      }
    }

个人资料屏幕代码:

class ProfileFargment extends StatefulWidget {
  final void Function(int) onButtonPressed;
  const ProfileFargment({Key key, this.onButtonPressed});
  @override
  _ProfileFragmentState createState() => _ProfileFragmentState();
}

class _ProfileFragmentState extends State<ProfileFargment> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.all(20.0),
          height: double.infinity,
          width: double.infinity,
          color: Colors.teal,
          child: GestureDetector(
            onTap: () {
              //Calling method changeTabMethod(0)
              // HomeScreen().createState().changeTabMethod(0);
              widget.onButtonPressed(0);
            },
            child: Container(
              margin: EdgeInsets.only(top: 20.0),
              height: 40.0,
              width: 150.0,
              color: Colors.white,
              child: Center(
                child: Text('Profile'),
              ),
            ),
          ),
        ),
      ),
    );
  }
}