Encaplsulating a widget for use in another dart file

Viewed 20

What I'm trying to achieve:

  • Have a BottomNavigationBar widget in its own class in its own dart file called navigationBar.dart
  • Have a main.dart file that has a Scaffold widget that calls this class to create the BottomNavigationBar widget
  • Then in the main.dart file I want to be able to set the BottomNavigationBar from navigationBar.dart and I want to be able to change the body of the Scaffold widget in the main.dart file depending on which index is selected in the BottomNavigationBar widget (check the comment in the main.dart file in the body property for a better explanation)

Here is my code below so far:

navigationBar.dart

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

class NavigationBar extends StatefulWidget {
  const NavigationBar({Key? key}) : super(key: key);

  @override
  State<NavigationBar> createState() => _NavigationBar();

}

class _NavigationBar extends State<NavigationBar> {
  
  int selectedIndex = 2;

  void _onItemTapped(int index) {
    setState(() {
      selectedIndex = index;
    });
  }
  @override
  Widget build(BuildContext context) {
  return BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
            backgroundColor: Colors.red,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
            backgroundColor: Colors.green,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
            backgroundColor: Colors.purple,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: 'Settings',
            backgroundColor: Colors.pink,
          ),
        ],
        currentIndex: selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      );
}

main.dart

import 'package:flutter/material.dart';
import 'components/navigationBar.dart';

void main() {
  runApp(const MaterialApp(home: App()));
}

class App extends StatefulWidget {
  const App({Key? key}) : super(key: key);

  @override
  State<App> createState() => _App();
}

class _App extends State<App> {
  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
    ),
    Text(
      'Index 1: Business',
    ),
    Text(
      'Index 2: School',
    ),
    Text(
      'Index 3: Settings',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    const navBar = navigationBar()
    return Scaffold(
        appBar: AppBar(
          title: const Text('Test App',
              style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'LogoFont',
                  fontSize: 30.0,
                  letterSpacing: 1.5)),
          centerTitle: true,
          backgroundColor: Colors.lightBlue[500],
          elevation: 0.0,
        ),
        backgroundColor: Colors.lightBlue[800],
        body: //something like this: _widgetOptions.elementAt(navbar.selectedIndex)
        ),
        bottomNavigationBar: navBar);
  }
}

Any ideas on how I could create what I need in the bullet points? Any help would be great, thanks

1 Answers

I think there is no way with stateful widget but you can do this by provider, like example below. Provider:

class MainViewProvider with ChangeNotifier , 
DiagnosticableTreeMixin{ 
int activeItem = 2;
changeActiveItem(int activeElement){
activeItem = activeElement;   
notifyListeners();                                         
}
}             

BottomNavBar Widget:

class BotNavWidget extends StatelessWidget {
const BotNavWidget({Key? key}) : super(key: key);
get context => null;
@override
Widget build(BuildContext context) {
final watch = context.watch<ColorsProvider>();
return Container(
  padding: EdgeInsets.symmetric(
      horizontal: getWidth(16), vertical: getHeight(10)),
  child: Container(
    height: SizeConfig.height! * .1,
    width: SizeConfig.width!,
    decoration: BoxDecoration(
        color: watch.colors[1],
        borderRadius: BorderRadius.circular(getWidth(20))),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        buildIcon(watch.bottomIcons[0], context, 0),
        buildIcon(watch.bottomIcons[1], context, 1),
        buildIcon(watch.bottomIcons[2], context, 2),
        buildIcon(watch.bottomIcons[3], context, 3),
        buildIcon(watch.bottomIcons[4], context, 4),
      ],
    ),
  ),
);
}

buildIcon(ColorFiltered icon, BuildContext context, int i) {
final read = context.read<MainViewProvider>();
final watch = context.watch<MainViewProvider>();
final watchColors = context.watch<ColorsProvider>().colors;
return InkWell(
  onTap: () async{
    read.changeActiveItem(i);
  },
  child: Container(
    padding: EdgeInsets.all(getWidth(15)),
    height: SizeConfig.height! * .07,
    width: SizeConfig.height! * .07,
    decoration: BoxDecoration(
        color: watch.activeItem == i ? watchColors[2] : Colors.transparent,
        borderRadius: BorderRadius.circular(getWidth(20))),
    child: SizedBox(
      height: getHeight(24),
      width: getHeight(24),
      child: icon
    ),
  ),
);
}
}

P.S: You can use custom BottomNavigationBar Widget instead of making it manually

Related