Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
152 views
in Technique[技术] by (71.8m points)

dart - [FLUTTER]: Programmatically change tabs in the CustomNavigator from SecondScreen to FirstScreen

I'm currently making an app with bottom navigator. And I have troubles with navigating from SecondScreen to the FirstScreen, programmatically, inside the SecondScreen file. But I have no idea how to do it. Because I can't have the access to the CustomNavigatorState part of the CustomNavigator class.

My main.dart file:

import 'package:flutter/material.dart';

import './screens/custom_navigator.dart';

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

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

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
       title: 'App Name',
       home: Scaffold(
          body: CustomNavigator(),
       ),
    );
  }
}

My custom_navigator.dart file, which includes CustomNavigator class and _CustomNavigatorState class:

import 'package:flutter/material.dart';

import './first_second.dart';
import './second_screen.dart';
import './third_screen.dart';

import '../widgets/tab_navigator.dart';

class CustomNavigator extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _CustomNavigatorState();
}

class _CustomNavigatorState extends State<CustomNavigator> {
  String _currentScreen = FirstScreen.route;
  List<String> _screenKeys = [
    FirstScreen.route,
    SecondScreen.route,
    ThirdScreen.route,
  ];
  Map<String, GlobalKey<NavigatorState>> _navigatorKeys = {
    FirstScreen.route: GlobalKey<NavigatorState>(),
    SecondScreen.route: GlobalKey<NavigatorState>(),
    ThirdScreen.route: GlobalKey<NavigatorState>(),
  };
  int _selectedIndex = 0;

  void changeTab(String tabItem, int index) {
    _selectedTab(tabItem, index);
  }

  void _selectedTab(String tabItem, int index) {
    if (tabItem == _currentScreen) {
      _navigatorKeys[tabItem].currentState.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentScreen = _screenKeys[index];
        _selectedIndex = index;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
            !await _navigatorKeys[_currentScreen].currentState.maybePop();
        if (isFirstRouteInCurrentTab) {
          if (_currentScreen != FirstScreen.route) {
            _selectedTab(FirstScreen.route, 1);
            return false;
          }
        }
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        resizeToAvoidBottomPadding: true,
        body: Stack(
          children: [
            _buildOffstageNavigator(FirstScreen.route),
            _buildOffstageNavigator(ScreenScreen.route),
            _buildOffstageNavigator(ThirdScreen.route),
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(
          onTap: (index) {
            _selectedTab(_screenKeys[index], index);
          },
          currentIndex: _selectedIndex,
          items: [
            BottomNavigationBarItem(
              label: 'First',
            ),
            BottomNavigationBarItem(
              label: 'Second',
            ),
            BottomNavigationBarItem(
              label: 'Third',
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildOffstageNavigator(String tabItem) {
    return Offstage(
      offstage: _currentScreen != tabItem,
      child: TabNavigator(
        navigatorKey: _navigatorKeys[tabItem],
        tabItem: tabItem,
      ),
    );
  }
}

TabNavigator class, where the screens added.

import 'package:flutter/material.dart';

import '../screens/first_screen.dart';
import '../screens/second_screen.dart';
import '../screens/third_screen.dart';

class TabNavigator extends StatelessWidget {
  final GlobalKey<NavigatorState> navigatorKey;
  final String tabItem;

  const TabNavigator({
    Key key,
    this.navigatorKey,
    this.tabItem,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Widget child;

    if (tabItem == FirstScreen.route) {
      child = FirstScreen();
    } else if (tabItem == SecondScreen.route) {
      child = SecondScreen();
    } else if (tabItem == ThirdScreen.route) {
      child = ThirdScreen();
    }

    return Navigator(
      key: navigatorKey,
      onGenerateRoute: (routeSettings) {
        return MaterialPageRoute(
          builder: (context) => child,
        );
      },
    );
  }
}

I tried to navigate with Navigator.push and Navigator.pushNamed, but it navigates inside SecondScreen without changing the BottomNavigationTabBars.

Navigator.of(context).push(
   MaterialPageRoute(
     builder: (_) => SecondScreen(),
   ),
);
Navigator.of(context).pushNamed(SecondScreen.route);

Also I can't use Provider, because I don't have access to _CustomNavigatorState class. Could anybody offer me any decision of the problem. Thanks.

question from:https://stackoverflow.com/questions/65871443/flutter-programmatically-change-tabs-in-the-customnavigator-from-secondscreen

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I notice you have the nested Scaffolds, it's probably better to move your BottomNavigationBar to the outer Scaffold so you only have one Scaffold in your app. For the body of the outter Scaffold you will have your Stack

Regarding the navigator issues. The body of your app in a Stack with three offstage widgets. Only one of the widgets is visible at a time. When changing between each Offstage widget you don't actually navigate to it, all you have to do is change your _currentScreen to which ever you would like. So if you're on page one and would like to "push" to page 2 then have something like

onPressed: () {
    SetState(() {
        _currentScreen = FirstScreen.route;
    }
}

Then when your body rebuilds from the setState it will set the FirstScreen to be onstage and all other screens to be offstage. Showing you the FirstScreen.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.9k users

...