Search code examples
flutterdartflutter-layoutflutter-cupertinoflutter-bottomnavigation

How do I make BottomNavigationBar page transition with Flutter's onWillpop?


I am using BottomNavigationBar in Flutter Project. This question is for line 30 "//TODO: back to the FirstTab". When a user is in the SecondTab or ThirdTab and the BackButton in the Android device is pressed, I want the user to go to the FirstTab. Now, in onWillpopScope, there is a process to pop when you can. It is used when the user is in NextPage. Then, when the user is not in the FirstTab (SecondTab or ThirdTab) and not in the NextTab, I want to move him to the FirstTab in onWillpopScope. (I want to force the BottomNavigationBar to switch.) How should I describe it? Please tell me.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<GlobalKey<NavigatorState>> navigatorKeys = [
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
  ];

  @override
  Widget build(BuildContext context) {
    int currentIndex = 0;
    return MaterialApp(
      home: WillPopScope(
        onWillPop: () async {
          final isFirstRouteInCurrentTab = await navigatorKeys[currentIndex].currentState.maybePop();

          if (isFirstRouteInCurrentTab) {
            if (currentIndex != 0) {
              //TODO: back to the FirstTab
              
              return false;
            }
          }

          return isFirstRouteInCurrentTab;
        },
        child: CupertinoTabScaffold(
          tabBar: CupertinoTabBar(
            items: <BottomNavigationBarItem>[
              BottomNavigationBarItem(label: 'Home', icon: Icon(Icons.home)),
              BottomNavigationBarItem(label: 'Search', icon: Icon(Icons.search)),
              BottomNavigationBarItem(label: 'Setting', icon: Icon(Icons.settings)),
            ],
            onTap: (index) {
              // back home only if not switching tab
              if (currentIndex == index) {
                switch (index) {
                  case 0:
                    navigatorKeys[index].currentState.popUntil((route) => route.isFirst);
                    break;
                  case 1:
                    navigatorKeys[index].currentState.popUntil((route) => route.isFirst);
                    break;
                  case 2:
                    navigatorKeys[index].currentState.popUntil((route) => route.isFirst);
                    break;
                }
              }
              currentIndex = index;
            },
            currentIndex: currentIndex,
          ),
          tabBuilder: (BuildContext context, int index) {
            return CupertinoTabView(
              navigatorKey: navigatorKeys[index],
              builder: (BuildContext context) {
                switch (index) {
                  case 0:
                    return FirstTab();
                  case 1:
                    return SecondTab();
                  case 2:
                    return ThirdTab();
                  default:
                    return FirstTab();
                }
              },
            );
          },
        ),
      ),
    );
  }
}

class FirstTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('first page now'),
      ),
      backgroundColor: Colors.red[200],
      child: Center(
        child: CupertinoButton(
          child: const Text('Next'),
          onPressed: () {
            Navigator.of(context).push(CupertinoPageRoute(builder: (context) => NextPage()));
          },
        ),
      ),
    );
  }
}

//Different color from Firsttab
class SecondTab extends StatelessWidget {}

//Different color from Firsttab
class ThirdTab extends StatelessWidget {}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('second page now'),
      ),
      backgroundColor: Colors.white,
      child: Center(
        child: CupertinoButton(
          child: const Text('Back'),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      ),
    );
  }
}

Solution

  • You can try to see it docs.

    I'll resume here. First you need to create a controller

    final CupertinoTabController _controller = CupertinoTabController();
    

    and add to your CupertinoTabScaffold like this

    CupertinoTabScaffold(
          ...
          controller: _controller,
    )
    

    in the end you change the page like this:

    _controller.index = 0,
    

    (this is how get and set work in Flutter)