위 링크를 순서대로 참고하여 프로젝트를 설정하고 진행하였다고 가정합니다. 이 포스팅은 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.dart
import '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, // 선택되지 않은 아이템 색상
),
);
}
}