【问题标题】:How to navigate to a different page on a different tab using CupertinoTabBar?如何使用 CupertinoTabBar 导航到不同选项卡上的不同页面?
【发布时间】:2026-02-20 19:35:02
【问题描述】:

我有两个选项卡 - Tab1 和 Tab2。 Tab1 有 3 页 - Tab1 Page1、Tab1 Page2、Tab1 Page3。

我希望能够从 Tab2 导航到 Tab1 Page2。我可以使用controller.index = 0 切换索引,但不确定如何导航到此选项卡的第 2 页。什么是干净的解决方案?

// main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cupertino Tab Bar Demo',
      theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
      home: SafeArea(child: Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage(this.title);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var navigatorKeyList = [GlobalKey<NavigatorState>(), GlobalKey<NavigatorState>()];
  var currentIndex = 0;
  var controller = CupertinoTabController(initialIndex: 0);

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      controller: controller,
      tabBar: CupertinoTabBar(
        onTap: (index) {
          if (currentIndex == index) {
            // Navigate to the tab's root route
            navigatorKeyList[index].currentState.popUntil((route) {
              return route.isFirst;
            });
          }
          currentIndex = index;
        },
        items: [
          BottomNavigationBarItem(title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
          BottomNavigationBarItem(title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
        ],
      ),
      tabBuilder: (BuildContext _, int index) {
        switch (index) {
          case 0:
            return CupertinoTabView(
              navigatorKey: navigatorKeyList[index],
              routes: {
                '/': (context) => WillPopScope(
                      child: Page1(),
                      onWillPop: () => Future<bool>.value(true),
                    ),
                'page1b': (context) => Page1b(),
                'page1c': (context) => Page1c(),
              },
            );
          case 1:
            return CupertinoTabView(
              navigatorKey: navigatorKeyList[index],
              routes: {
                '/': (context) => WillPopScope(
                      child: Page2(controller),
                      onWillPop: () => Future<bool>.value(true),
                    )
              },
            );
          default:
            return Text('Index must be less than 2');
        }
      },
    );
  }
}

// Tab1 Page1
class Page1 extends StatelessWidget {
  Page1();

  @override
  Widget build(BuildContext context) {
    return BaseContainer(
      Column(
        children: <Widget>[
          Container(
            child: Text(
              'Tab1',
              style: Theme.of(context).textTheme.headline4,
            ),
          ),
          FlatButton(
            color: Colors.lightGreen,
            child: Text('Go to Tab1 Page2'),
            onPressed: () {
              Navigator.pushNamed(context, 'page1b');
            },
          )
        ],
      ),
    );
  }
}

// Tab1 Page2
class Page1b extends StatelessWidget {
  Page1b();

  @override
  Widget build(BuildContext context) {
    return BaseContainer(
      Column(
        children: <Widget>[
          Container(
            child:
                Text('Tab1 Page2', style: Theme.of(context).textTheme.headline4),
          ),
          FlatButton(
            color: Colors.lightGreen,
            child: Text('Go to Tab1 Page3'),
            onPressed: () {
              Navigator.pushNamed(context, 'page1c');
            },
          )
        ],
      ),
    );
  }
}

// Tab2
class Page2 extends StatelessWidget {
  final CupertinoTabController controller; 

  const Page2(this.controller);

  @override
  Widget build(BuildContext context) {
    return BaseContainer(
      Column(
        children: <Widget>[
          Container(
            child: Text(
              'Tab2',
              style: Theme.of(context).textTheme.headline4,
            ),
          ),
          FlatButton(
            color: Colors.lightGreen,
            child: Text('Go to Tab1 Page2 (TODO)'),
            onPressed: () {
              // TODO I want this to go to Tab1 Page2
              this.controller.index = 0;
              Navigator.of(context).pushNamed('page1b');
            },
          )
        ],
      ),
    );
  }
}

【问题讨论】:

    标签: flutter


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    第 1 步:您可以将navigatorKeyList[0]) 传递给Page2
    第 2 步:致电 navigatorKey.currentState.pushNamed("page1b"); 并更改 index

    代码sn-p

    return CupertinoTabView(
                  navigatorKey: navigatorKeyList[index],
                  routes: {
                    '/': (context) => WillPopScope(
                          child: Page2(controller, navigatorKeyList[0]),
                          onWillPop: () => Future<bool>.value(true),
                        )
                  },
                );
    ...         
    class Page2 extends StatelessWidget {
      final CupertinoTabController controller;
      final GlobalKey<NavigatorState> navigatorKey;
      const Page2(this.controller, this.navigatorKey);
      ...
        FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page2 (TODO)'),
                onPressed: () {
                  navigatorKey.currentState.pushNamed("page1b");
                  this.controller.index = 0;
                },
              )
    

    工作演示

    完整代码

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Cupertino Tab Bar Demo',
          theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
          home: SafeArea(
              child:
                  Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage(this.title);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var navigatorKeyList = [
        GlobalKey<NavigatorState>(),
        GlobalKey<NavigatorState>()
      ];
      var currentIndex = 0;
      var controller = CupertinoTabController(initialIndex: 0);
    
      @override
      Widget build(BuildContext context) {
        return CupertinoTabScaffold(
          controller: controller,
          tabBar: CupertinoTabBar(
            onTap: (index) {
              if (currentIndex == index) {
                // Navigate to the tab's root route
                navigatorKeyList[index].currentState.popUntil((route) {
                  return route.isFirst;
                });
              }
              currentIndex = index;
            },
            items: [
              BottomNavigationBarItem(
                  title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
              BottomNavigationBarItem(
                  title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
            ],
          ),
          tabBuilder: (BuildContext _, int index) {
            switch (index) {
              case 0:
                return CupertinoTabView(
                  navigatorKey: navigatorKeyList[index],
                  routes: {
                    '/': (context) => WillPopScope(
                          child: Page1(),
                          onWillPop: () => Future<bool>.value(true),
                        ),
                    'page1b': (context) => Page1b(),
                    'page1c': (context) => Page1c(),
                  },
                );
              case 1:
                return CupertinoTabView(
                  navigatorKey: navigatorKeyList[index],
                  routes: {
                    '/': (context) => WillPopScope(
                          child: Page2(controller, navigatorKeyList[0]),
                          onWillPop: () => Future<bool>.value(true),
                        )
                  },
                );
              default:
                return Text('Index must be less than 2');
            }
          },
        );
      }
    }
    
    // Tab1 Page1
    class Page1 extends StatelessWidget {
      Page1();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text(
                  'Tab1',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page2'),
                onPressed: () {
                  Navigator.pushNamed(context, 'page1b');
                },
              )
            ],
          ),
        );
      }
    }
    
    // Tab1 Page2
    class Page1b extends StatelessWidget {
      Page1b();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text('Tab1 Page2',
                    style: Theme.of(context).textTheme.headline4),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page3'),
                onPressed: () {
                  Navigator.pushNamed(context, 'page1c');
                },
              )
            ],
          ),
        );
      }
    }
    
    class Page1c extends StatelessWidget {
      Page1c();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text('Tab1 Page2',
                    style: Theme.of(context).textTheme.headline4),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page3'),
                onPressed: () {
                  Navigator.pushNamed(context, 'page1c');
                },
              )
            ],
          ),
        );
      }
    }
    
    // Tab2
    class Page2 extends StatelessWidget {
      final CupertinoTabController controller;
      final GlobalKey<NavigatorState> navigatorKey;
      const Page2(this.controller, this.navigatorKey);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text(
                  'Tab2',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page2 (TODO)'),
                onPressed: () {
                  navigatorKey.currentState.pushNamed("page1b");
                  this.controller.index = 0;
                },
              )
            ],
          ),
        );
      }
    }
    

    完整代码2

        import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Cupertino Tab Bar Demo',
          theme: ThemeData(primarySwatch: Colors.blue, textTheme: TextTheme()),
          home: SafeArea(
              child:
                  Scaffold(body: MyHomePage('Cupertino Tab Bar Demo Home Page'))),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage(this.title);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var navigatorKeyList = [
        GlobalKey<NavigatorState>(),
        GlobalKey<NavigatorState>()
      ];
      int currentIndex = 0;
      var controller = CupertinoTabController(initialIndex: 0);
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return CupertinoTabScaffold(
          controller: controller,
          tabBar: CupertinoTabBar(
            onTap: (index) {
              if (currentIndex == index) {
                // Navigate to the tab's root route
                navigatorKeyList[index].currentState.popUntil((route) {
                  return route.isFirst;
                });
              }
              currentIndex = index;
            },
            items: [
              BottomNavigationBarItem(
                  title: Text('Tab 1'), icon: Icon(Icons.ac_unit)),
              BottomNavigationBarItem(
                  title: Text('Tab 2'), icon: Icon(Icons.ac_unit)),
            ],
          ),
          tabBuilder: (BuildContext _, int index) {
            switch (index) {
              case 0:
                return CupertinoTabView(
                  navigatorKey: navigatorKeyList[index],
                  routes: {
                    '/': (context) => WillPopScope(
                          child: Page1(controller, navigatorKeyList[1]),
                          onWillPop: () => Future<bool>.value(true),
                        ),
                    'page1b': (context) => Page1b(),
                    'page1c': (context) => Page1c(),
                  },
                );
              case 1:
                return CupertinoTabView(
                  navigatorKey: navigatorKeyList[index],
                  routes: {
                    '/': (context) => WillPopScope(
                          child: Page2(controller, navigatorKeyList[0]),
                          onWillPop: () => Future<bool>.value(true),
                        )
                  },
                );
              default:
                return Text('Index must be less than 2');
            }
          },
        );
      }
    }
    
    // Tab1 Page1
    class Page1 extends StatelessWidget {
      final CupertinoTabController controller;
      final GlobalKey<NavigatorState> navigatorKey;
      const Page1(this.controller, this.navigatorKey);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text(
                  'Tab1',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab2 Page2'),
                onPressed: () async {
                  controller.index = 1;
                  await Future.delayed(Duration(seconds: 1), () {});
                  navigatorKey.currentState.pushNamed("/");
                },
              )
            ],
          ),
        );
      }
    }
    
    // Tab1 Page2
    class Page1b extends StatelessWidget {
      Page1b();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text('Tab1 Page2',
                    style: Theme.of(context).textTheme.headline4),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page3'),
                onPressed: () {
                  Navigator.pushNamed(context, 'page1c');
                },
              )
            ],
          ),
        );
      }
    }
    
    class Page1c extends StatelessWidget {
      Page1c();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text('Tab1 Page2',
                    style: Theme.of(context).textTheme.headline4),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page3'),
                onPressed: () {
                  Navigator.pushNamed(context, 'page1c');
                },
              )
            ],
          ),
        );
      }
    }
    
    // Tab2
    class Page2 extends StatelessWidget {
      final CupertinoTabController controller;
      final GlobalKey<NavigatorState> navigatorKey;
      const Page2(this.controller, this.navigatorKey);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                child: Text(
                  'Tab2',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab1 Page2 (TODO)'),
                onPressed: () async {
                  navigatorKey.currentState.pushNamed("page1b");
                  await Future.delayed(Duration(seconds: 1), () {});
                  this.controller.index = 0;
                },
              )
            ],
          ),
        );
      }
    }
    

    完整代码3

    return CupertinoTabView(
              navigatorKey: navigatorKeyList[index],
              routes: {
                '/': (context) => WillPopScope(
                      child: Page1(controller, navigatorKeyList),
                      onWillPop: () => Future<bool>.value(true),
                    ),
                'page2b': (context) => Page2b(),
                'page3b': (context) => Page3b(),
              },
            );
    
    ...
    import 'package:cupertino_tab_bar/base_widget.dart';
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    class Page1 extends StatelessWidget {
      final CupertinoTabController controller;
      final List<GlobalKey<NavigatorState>> navigatorKeyList;
      const Page1(this.controller, this.navigatorKeyList);
    
      @override
      Widget build(BuildContext context) {
        return BaseContainer(
          Column(
            children: <Widget>[
              Container(
                child: Text(
                  'Tab1',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab2 Page2'),
                onPressed: () async{
                  controller.index = 1;
                  await Future.delayed(Duration(seconds: 1), () {});
                  navigatorKeyList[1].currentState.pushNamed("page2b");
                },
              ),
              FlatButton(
                color: Colors.lightGreen,
                child: Text('Go to Tab3 Page2'),
                onPressed: () async{
                  controller.index = 2;
                  await Future.delayed(Duration(seconds: 1), () {});
                  navigatorKeyList[2].currentState.pushNamed("page3b");Navigator.pushNamed(context, 'page3b');
                },
              )
            ],
          ),
        );
      }
    }
    

    【讨论】:

    • 我注意到 navigatorKey.currentState 为 null,因为它尚未初始化(我假设是因为尚未单击该选项卡)。
    • 是的。假设你的第一页是 1,你可以用 0 初始化并像这样转到 1,var currentIndex = 0; var 控制器 = CupertinoTabController(initialIndex: 0); @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { currentIndex = 1; controller.index = 1; }); super.initState(); }
    • 不,但我的第一页总是 0。
    • 无法在我的示例代码中重现。当初始页面时,也可以与我的 cmets 一起使用。
    • 测试场景是这样的——从 Tab1 Page1 开始。我想从 Tab1 Page1 导航到 Tab2 Page2。但是 navigatorKey.currentState 对于 tab2 是 null 因为它还没有被初始化。
    最近更新 更多