Sevenzzz
Sevenzzz

Reputation: 58

Flutter how to change the parent BottomNavigationBar index from a child widget

So I have recently started my first project in flutter, I completed the full UI layout and am now doing the whole logic part of the front-end, most of my onTap behavior is working, but I have come to the following situation I do not know how to tackle.

I have four files which contains all the UI.
widget0.dart
widget1.dart
widget2.dart

These files each hold the StatefullWidget which are being build by the BottomNavigationBar.

main.dart
This file contains my main() =>runApp class and function. My MaterialApp contains a Scaffold with a BottomNavigationBar. This works as intended and I am being able to switch between each of the 3 widgets.

However in my widget0.dart file I have a button which should change the index of the BottomNavigationBar from my main.dart file from 0 to 2 (to build the widget from widget2.dart).

I have tried to wrap up the value that holds the index for the navigation bar in a separate static class, so I could setState((){ StaticClass.index = 2}) in the button onTap(), but this doesn't work, and actually freezes the navigation bar to its initial value.

An answer somewhere here on stackoverflow suggested that each of the Widgets should have it's own Scaffold and navigationbar, however I am sure there must be a cleaner way.

So what is the most Fluttery way to achieve my goal?

Thanks in advance.

Upvotes: 2

Views: 6563

Answers (2)

Roddy R
Roddy R

Reputation: 1470

You can use a InheritedNotifier to control the index. Then you can access it anywhere in your app.

  1. Create a new class

bottom_nav_scope.dart

import 'package:flutter/material.dart';

class BottomNavState extends ChangeNotifier {
  int _navIndex = 0;

  int get navIndex => _navIndex;

  set navIndex(int value) {
    _navIndex = value;
    notifyListeners();
  }
}

class BottomNavScope extends InheritedNotifier<BottomNavState> {
  const BottomNavScope({
    required BottomNavState notifier,
    required Widget child,
    Key? key,
  }) : super(key: key, notifier: notifier, child: child);

  static BottomNavState? of(BuildContext context) {
    return context
        .dependOnInheritedWidgetOfExactType<BottomNavScope>()
        ?.notifier;
  }
}
  1. Wrap your root stateful widget (such as app) with:

NOTE: This must be above the widget that builds the BottomNavigationBar. Also it needs to be a stateful widget.

app.dart

final bottomNav = BottomNavState();

@override
Widget build(BuildContext context) {
  BottomNavScope(notifier: bottomNav, child: ...). //wrap your root widget with this
  1. In your BottomNavigationBar
BottomNavigationBar(
   currentIndex: BottomNavScope.of(context)!.navIndex, ...)
  1. Usage
BottomNavScope.of(context)!.navIndex = 2;

Upvotes: 0

dshukertjr
dshukertjr

Reputation: 18650

You can pass a function as a parameter to widget0 and in that function can change the index value like this:

class ParentWidgetState extends State<ParentWidget> {

  int _index = 0;

  void goToWidget2() {
    setState(() {
          _index = 2;
        });
  }

  Widget body() {
    switch(_index) {
      case 0: 
        return Widget0(goToWidget2);
      case 1: 
        return Widget1();
      case 2: 
        return Widget2();
    }
    return Container();
  }

  @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: body(),
        bottomNavigationBar: BottomNavigationBar(
        currentIndex: _index,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
          ),
        ],
      ),
      );
    }
}

class Widget0 extends StatelessWidget {
  Widget0(this.goToWidget2);
  final void Function() goToWidget2;
  @override
    Widget build(BuildContext context) {
      return Center(child: FlatButton(
        onPressed: goToWidget2,
        child: Text("Go To Widget 2"),
      ),);
    }
}
class Widget1 extends StatelessWidget {
  @override
    Widget build(BuildContext context) {
      return Center(child: Text("widget 1"),);
    }
}
class Widget2 extends StatelessWidget {
  @override
    Widget build(BuildContext context) {
      return Center(child: Text("widget 2"),);
    }
}

Upvotes: 12

Related Questions