- Goals, requirements, initial setup, and overview: Link
- Login-page branching with FlutterSecureStorage: Link
- Setting up a bottom navigation bar: Link
This post assumes you have configured the project by following those links in order. It was written for Flutter 3.24.
đĻ lib
âŖ đ model // ë°ė´í° ëŗ´ę´íë ëĒ¨ë¸ í´ë(ė´ë˛ íŦė¤í
ėėë ėŦėŠíė§ ėė)
âŖ đ view // í늴ė ęĩŦėąíë 롰 í´ë
â âŖ đ tabs // í 4ę°ëĨŧ ęĩŦėąíë í늴
â â âŖ đ home_screen.dart
â â âŖ đ notifications_screen.dart
â â âŖ đ profile_screen.dart
â â â đ search_screen.dart
â âŖ đ external_screen.dart
â âŖ đ login_page.dart
â â đ main_page.dart
âŖ đ viewModel // ë°ė´í°ė í늴ė ėë viewModel í´ë
â â đ auth_service.dart
â đ main.dartimport 'package:flutter/material.dart';
class ExternalScreen extends StatelessWidget {
const ExternalScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('External Screen'), // ėļę° í늴 ė ëĒŠ
),
body: const Center(
child: Text('External Screen', style: TextStyle(fontSize: 24)),
),
);
}
}import 'package:flutter/material.dart';
import 'package:navigationbar_example/view/external_screen.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Home Screen', style: TextStyle(fontSize: 24)),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ExternalScreen()));
},
icon: const Icon(Icons.next_plan))
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:navigationbar_example/view/tabs/home_screen.dart';
import 'package:navigationbar_example/view/tabs/notifications_screen.dart';
import 'package:navigationbar_example/view/tabs/profile_screen.dart';
import 'package:navigationbar_example/view/tabs/search_screen.dart';
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
MainPageState createState() => MainPageState();
}
class MainPageState extends State<MainPage> {
int _currentIndex = 0; // íėŦ ė íë íė ė¸ëąė¤
// ę° íėė ëŗ´ėŦė¤ í늴 ëĻŦė¤í¸
final List<Widget> _pages = [
const HomeScreen(), // ė˛Ģ ë˛ė§¸ í í늴
const SearchScreen(), // ë ë˛ė§¸ í í늴
const NotificationsScreen(), // ė¸ ë˛ė§¸ í í늴
ProfileScreen(), // ë¤ ë˛ė§¸ í í늴
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack( // ę° íë§ë¤ ė¤íė ė ė§íëëĄ ė¤ė
index: _currentIndex,
children: List.generate(_pages.length, (index) {
return Navigator( // í ė í ė íė´ė§ ė´ëė ėí Navigator
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => _pages[index],
);
},
);
}),
), // ė íë íė í늴ė ëŗ´ėŦė¤ ėė ¯
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex, // ė íë í ė¸ëąė¤
onTap: (index) {
setState(() {
_currentIndex = index; // í ė í ė ėí ė
ë°ė´í¸
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications),
label: 'Notifications',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
selectedItemColor: Colors.blue, // ė íë ėė´í
ėė
unselectedItemColor: Colors.grey, // ė íëė§ ėė ėė´í
ėė
),
);
}
}
import 'package:flutter/material.dart';
import 'package:navigationbar_example/view/tabs/home_screen.dart';
import 'package:navigationbar_example/view/tabs/notifications_screen.dart';
import 'package:navigationbar_example/view/tabs/profile_screen.dart';
import 'package:navigationbar_example/view/tabs/search_screen.dart';
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
MainPageState createState() => MainPageState();
}
class MainPageState extends State<MainPage> {
int _currentIndex = 0; // íėŦ ė íë íė ė¸ëąė¤
// ę° íėė ëŗ´ėŦė¤ í늴 ëĻŦė¤í¸
final List<Widget> _pages = [
const HomeScreen(), // ė˛Ģ ë˛ė§¸ í í늴
const SearchScreen(), // ë ë˛ė§¸ í í늴
const NotificationsScreen(), // ė¸ ë˛ė§¸ í í늴
ProfileScreen(), // ë¤ ë˛ė§¸ í í늴
];
final List<GlobalKey<NavigatorState>> _navigatorKeys = [ // ę° íė NavigatorKey
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
];
void _onTap(int index) { // í ė í ė í¸ėļí í¨ė
if (index == _currentIndex) {
_navigatorKeys[index].currentState?.popUntil((route) => route.isFirst); // íė´ ė´ë¯¸ ė íë ėíėė ë¤ė ė íí ę˛Ŋė° ėĩėë¨ íė´ė§ëĄ ė´ë
} else {
setState(() {
_currentIndex = index;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: List.generate(_pages.length, (index) {
return Navigator(
key: _navigatorKeys[index], // ę° íė NavigatorKey ė¤ė
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => _pages[index],
);
},
);
}),
), // ė íë íė í늴ė ëŗ´ėŦė¤ ėė ¯
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex, // ė íë í ė¸ëąė¤
onTap: _onTap, // í ė í ė í¸ėļí í¨ė
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications),
label: 'Notifications',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
selectedItemColor: Colors.blue, // ė íë ėė´í
ėė
unselectedItemColor: Colors.grey, // ė íëė§ ėė ėė´í
ėė
),
);
}
}