How to make a Navigator with the same destination as BottomNavig

ghz 8months ago ⋅ 87 views

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.
            ),
          ),
        ),
      ],
    );
  }
}

Answers

It looks like you've made significant progress on your Flutter app! Let's address the issues you mentioned and make the necessary adjustments to achieve the desired behavior.

Issue 1: Transition to CamScreen leaves app.dart

To address this issue, we need to ensure that the transition from the button in the HomeScreen to the CamScreen does not leave the BasePage widget. We'll modify the changeIndex function to handle this transition properly.

Issue 2: Updating BottomNavigationBar selection

When transitioning between screens, you want the corresponding icon in the BottomNavigationBar to light up. We'll update the logic to achieve this behavior.

Issue 3: Reviewing the UI

We'll review the UI and make any necessary adjustments for better usability.

Proposed Solution:

Update BasePage widget:

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

  void changeIndex(int index) {
    setState(() {
      _currentIndex = index;
      _pageController.jumpToPage(index);
    });
  }

  @override
  Widget build(BuildContext context) {
    var tabItems = {
      '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: tabItems.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: tabItems.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) {
            changeIndex(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,
      ),
    );
  }
}

Update HomeScreen widget:

class HomeScreen extends StatelessWidget {
  final PageController pageController;
  final void Function(int) changeIndex;

  const HomeScreen({Key? key, required this.pageController, required this.changeIndex}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: () {
              changeIndex(1); // Transition to CamScreen
            },
            child: Container(
              // Add your button UI here
              alignment: Alignment.center,
              child: Text(
                'Go to Cam Screen',
                style: TextStyle(fontSize: 20),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

With these adjustments, tapping the button in HomeScreen will transition to CamScreen without leaving BasePage, and the BottomNavigationBar selection will update accordingly.