beginner T
beginner T

Reputation: 15

How to make a Navigator with the same destination as BottomNavigationBar?

I want to add a button to 'src/screens/home.dart' that has the same transition as the BottomNavigationBar in 'src/app.dart'. Of course, keeping the AppBar and BottomNavigationBar.

In my code, if I move from the button in home to cam Screen, it leaves app.dart. It is also plausible that the UI should be reviewed.

After that transition, I want the BottomNavigationBar icon to light up. When moving to a screen with no icons, I want all icons to be dimmed. Same as the 'app.dart _buildIcon' process.

I started learning Flutter yesterday, so if there's any weird code, please let me know. Thank you.

enter image description here

Edit:.
I gave HomeScreen() a PageController and was able to take over the AppBar and BottomBar, but the BottomBar selection is not updated.

main.dart:

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

import 'src/app.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,]);
  runApp(
    const MyApp()
  );
}

src/app.dart:

import 'package:flutter/material.dart';

import 'screens/home.dart';
import 'screens/cam.dart';
import 'screens/setting.dart';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent,
      ),
      home: BasePage(),
    );
  }
}

class BasePage extends StatefulWidget{
  @override
  _BasePage createState() => _BasePage();
}


class _BasePage extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {

    var TabItem = {
      'home':[0, Icons.home, Colors.green, HomeScreen(pageController: _pageController)],
      'cam':[1, Icons.video_camera_back, Colors.lightGreen, const CamScreen()],
      'setting':[2, Icons.settings, Colors.yellow, const SettingScreen()]
    };

    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: PageView(
        controller: _pageController,
        physics: const NeverScrollableScrollPhysics(),
        children: TabItem.values.map((value) => value[3] as Widget).toList(),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.entries.map(
            (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.value[1] as IconData, tabItem.value[2]as Color, selected: _currentIndex == tabItem.value[0]),
              label: tabItem.key,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,          
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3); 
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

src/screens/home.dart:

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  final PageController pageController;
  HomeScreen({super.key, required this.pageController,});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: (){pageController.jumpToPage(1);},
            child: Container(
              // Omit the code here.
            ),
          ),
        ),
      ],
    );
  }
}

src/screens/cam.dart

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:
          const Center(child: Text('camera', style: TextStyle(fontSize: 32.0))),
    );
  }
}

SOLVED src/app.dart

import 'package:flutter/material.dart';

import 'screens/home.dart';
import 'screens/cam.dart';
import 'screens/setting.dart';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent,
      ),
      home: BasePage(),
    );
  }
}

class BasePage extends StatefulWidget{
  @override
  _BasePage createState() => _BasePage();
}

class _BasePage extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  void changeIndex(index){
    setState(() {
      _currentIndex = index;
      _pageController.jumpToPage(index);
    });
  }
  
  @override
  Widget build(BuildContext context) {

    var TabItem = {
      'home':[0, Icons.home, Colors.green, HomeScreen(pageController: _pageController, changeIndex: changeIndex,)],
      'cam':[1, Icons.video_camera_back, Colors.lightGreen, const CamScreen()],
      'setting':[2, Icons.settings, Colors.yellow, const SettingScreen()]
    };

    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: PageView(
        controller: _pageController,
        physics: const NeverScrollableScrollPhysics(),
        children: TabItem.values.map((value) => value[3] as Widget).toList(),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.entries.map(
            (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.value[1] as IconData, tabItem.value[2]as Color, selected: _currentIndex == tabItem.value[0]),
              label: tabItem.key,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,          
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3); 
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

src/screens/home.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  final PageController pageController;
  final void Function(int) changeIndex;
  const HomeScreen({super.key, required this.pageController, required this.changeIndex});


  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: (){changeIndex(1);},
            child: Container(
              // Omit the code here.
            ),
          ),
        ),
      ],
    );
  }
}

Upvotes: 0

Views: 117

Answers (2)

Ultranmus
Ultranmus

Reputation: 460

Check out the below code. In your edited code you were handling MyApp widget incorrectly, you need to pass a home widget to MaterialApp. And you don' need onPageChange here beacuse it is used when you scroll in PageView and want to do some changes on page change but in your case you are manually changing it on bottom navigation bar click

void main()  {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    // postData();
    // fetchIPAddress();
  }

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BasePage(),
    );
  }
}

enum TabItem {
  home(
      title: 'home',
      icon: Icons.home,
      color: Colors.green,
      page: HomeScreen()
  ),
  cam(
      title: 'cam',
      icon: Icons.video_camera_back,
      color: Colors.lightGreen,
      page: CamScreen()
  ),
  setting(
      title: 'setting',
      icon: Icons.settings,
      color: Colors.cyan,
      page: SettingScreen()
  );

  const TabItem({
    required this.title,
    required this.icon,
    required this.color,
    required this.page,
  });
  final String title;
  final IconData icon;
  final Color color;
  final Widget page;
}

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

  @override
  State<BasePage> createState() => _BasePageState();
}

class _BasePageState extends State<BasePage> {
  final _pageController = PageController();
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        toolbarHeight: MediaQuery.of(context).size.height / 16,
        title: Image.asset('assets/images/logo.png', width: 200, fit: BoxFit.contain,),
        centerTitle: true,
      ),

      body: Expanded(
        child: PageView(
          controller: _pageController,
          physics: const NeverScrollableScrollPhysics(),
          children: TabItem.values.map(
                  (tabItem) => tabItem.page
          ).toList(),
        ),
      ),

      bottomNavigationBar: SizedBox(
        height: MediaQuery.of(context).size.height /8,
        child:BottomNavigationBar(
          currentIndex: _currentIndex,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          items: TabItem.values.map(
                (tabItem) => BottomNavigationBarItem(
              icon: _buildIcon(tabItem.icon, tabItem.color, selected: _currentIndex==tabItem.index),
              label: tabItem.title,
            ),
          ).toList(),
          onTap: (index) {
            setState(() {
              _currentIndex = index;
              _pageController.jumpToPage(index);
            });
          },
          type: BottomNavigationBarType.fixed,
        ),
      ),
    );
  }

  Widget _buildIcon(IconData icon, Color color, {bool selected=false}) {
    Color filteredColor = selected ? color : color.withOpacity(0.3);
    return Container(
      width: 60, height: 60,
      decoration: BoxDecoration(shape: BoxShape.circle, color: filteredColor),
      child: Icon(icon, size: 50, color: Colors.white,),
    );
  }
}

Edit: The prblm when you click a btn on HomeScreen and go to other page, remove appbar and bottom nav bar is because you are using Navigator.push(). What you want to do is go from one page to another in pageview then use _pageController.jumpTo(). Just pass the controller to pages, which involve going to other pages. When you uses Navigator you are changing the whole screen but that's not what we want. We only want to change pages in page view to do that uses pageViewController

Upvotes: 0

iStornZ
iStornZ

Reputation: 858

Maybe you can give a try to PageView widget.

Just wrap the PageView in a Expanded widget & wrap it with your appbar & bottom tabbar. To change page, use the page view controller, the animation will be animated (can be disabled of course).

https://api.flutter.dev/flutter/widgets/PageView-class.html

Upvotes: 0

Related Questions