Search code examples
flutterflutter-layoutflutter-bottomnavigation

Flutter: How to use a button that has the same effect as clicking on a BottomNavigationBar?


I have a Dart file named page0.dart and this only includes a BottomNavigationBar. BottomNavigationBar has 2 items in it which redirects me to dashboard.dart and target.dart, the navigation via the BottomNavigationBar works as expected.

Now the problem: I need a button on dashboard.dart that should redirect me to target.dart, but keep the ButtomNavigationBar visible.

I am redirecting with Navigator.push, but that opens target.dart directly and skips page0.dart I think.

Screenshots are below. Please watch them for better understanding my problem.

Here are the code samples:

page0.dart:

import 'package:flutter/material.dart';
import 'package:navbartest/dashboard.dart';
import 'package:navbartest/target.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key, required String title}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      bottomNavigationBar: BottomNavBar(),
    );
  }
}

class BottomNavBar extends StatefulWidget {
  const BottomNavBar({super.key});

  @override
  State<BottomNavBar> createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int _pageIndex = 0;

  final List<Widget> _tabList = const [
    Dashboard(),
    Target(),
  ];

  Widget? onItemTap(int index) {
    setState(() {
      _pageIndex = index;
    });
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        _tabList.elementAt(_pageIndex),
        Padding(
          padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
          child: Align(
            alignment: const Alignment(0.0, 1.0),
            child: ClipRRect(
              borderRadius: const BorderRadius.all(
                Radius.circular(20),
              ),
              child: BottomNavigationBar(
                backgroundColor: const Color(0xff565656),
                type: BottomNavigationBarType.fixed,
                showSelectedLabels: false,
                showUnselectedLabels: false,
                unselectedItemColor: Colors.white,
                selectedItemColor: Colors.white,
                onTap: onItemTap,
                items: [
                  BottomNavigationBarItem(
                    icon: const Icon(Icons.home),
                    label: "Dashboard",
                  ),
                  BottomNavigationBarItem(
                    icon: const Icon(Icons.car_repair),
                    label: "Target",
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}

dashboard.dart

import 'package:navbartest/target.dart';

class Dashboard extends StatelessWidget {
  const Dashboard({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: Container(
            width: 120,
            height: 20,
            color: Colors.blue,
            child: InkResponse(
              onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const Target()),
                );
              },
              child: Text('navigate to target'),
            ),
          ),
        ),
      ),
    );
  }
}

target.dart:


class Target extends StatelessWidget {
  const Target({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Text('target'),
      ),
    );
  }
}

when the app is started, it looks like this
when I click the blue button to navigate, it looks like this (NavBar is gone!)
when I click the symbol in the navbar redirecting me to target.dart, it looks like this (thats how I want it with the blue button too!)


Solution

  • actually you need to use a state management for this type of actions , but I found a work around in your case , I will set the classes next Just replace them with your classes and it will work.

    1 - page0.dart:

    import 'target.dart';
    import 'package:flutter/material.dart';
    import 'dash.dart';
    
    class BottomNavBar extends StatefulWidget {
      const BottomNavBar({super.key});
    
      @override
      State<BottomNavBar> createState() => BottomNavBarState();
    }
    
    class BottomNavBarState extends State<BottomNavBar> {
    
      late int _pageIndex;
      late final List<Widget> _tabList;
    
      Widget? onItemTap(int index) {
        setState(() {
          _pageIndex = index;
        });
        return null;
      }
    
      @override
      void initState(){
        super.initState();
        _pageIndex = 0;
    
        _tabList = [
          Dashboard(ref:(int number){
            setState(() {
              _pageIndex = number;
            });
          }),
          const Target(),
        ];
      }
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            _tabList.elementAt(_pageIndex),
            Padding(
              padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
              child: Align(
                alignment: const Alignment(0.0, 1.0),
                child: ClipRRect(
                  borderRadius: const BorderRadius.all(
                    Radius.circular(20),
                  ),
                  child: BottomNavigationBar(
                    backgroundColor: const Color(0xff565656),
                    type: BottomNavigationBarType.fixed,
                    showSelectedLabels: false,
                    showUnselectedLabels: false,
                    unselectedItemColor: Colors.white,
                    selectedItemColor: Colors.white,
                    onTap: onItemTap,
                    items: [
                      BottomNavigationBarItem(
                        icon: const Icon(Icons.home),
                        label: "Dashboard",
                      ),
                      BottomNavigationBarItem(
                        icon: const Icon(Icons.car_repair),
                        label: "Target",
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        );
      }
    }
    

    2 - dashboard.dart :

    import 'package:flutter/material.dart';
    
    class Dashboard extends StatelessWidget {
      const Dashboard({super.key, required this.ref});
    
      final Function(int)? ref ;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
            child: Center(
              child: Container(
                width: 120,
                height: 20,
                color: Colors.blue,
                child: InkResponse(
                  onTap: ()=>ref!(1),
                  child: Text('navigate to target'),
                ),
              ),
            ),
          ),
        );
      }
    }
    

    3 - target.dart:

    import 'package:flutter/material.dart';
    
    class Target extends StatelessWidget {
      const Target({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
            child: Text('target'),
          ),
        );
      }
    }
    

    remove the import and re import for the right paths in your application file , but this is a work around and you should use the state management .