1

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.

Sevenzzz
  • 48
  • 2
  • 7

2 Answers2

11

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"),);
    }
}
VipiN Negi
  • 2,994
  • 3
  • 24
  • 47
dshukertjr
  • 15,244
  • 11
  • 57
  • 94
  • Is it possible to pass a parameter(int,string etc) as an argument for the callback function? If so how would that be implemented? – Lallawmzuala khawlhring Aug 23 '20 at 09:20
  • this does not work with today's flutter.. which is always the problem for me. – Bhikkhu Subhuti Aug 15 '21 at 14:28
  • @BhikkhuSubhuti It should still work. If you post a question with your code on stack overflow and paste the link here, I can take a look at it! – dshukertjr Aug 16 '21 at 03:14
  • 1
    @dshukertjr I finally got it to work. I think the modern flutter does not allow this code to work.. because i tried to compile it with null safety and other "modern" settings. Here was my issue on stackOverflow. solved https://stackoverflow.com/questions/68792794/flutter-pass-a-callback-function-to-child-stateful-widget-modern-flutter/68797359#68797359 – Bhikkhu Subhuti Aug 16 '21 at 04:19
0

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;
Roddy R
  • 1,222
  • 10
  • 10