2022.10.14 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기 #2. 기본 설정
카카오가 터지는 바람에 몇일 블로그를 못썼네;;; 망할 카카오.. 다른데로 블로그를 옮길까봐! ㅎㅎ 일단 앱 만들던건 만들고 ㅋ
기본 설정까지하고 지나갔는데 약간 진도가 나갔어. 소셜차트는 4개의 탭으로 구성되는데 그리고 각 탭은 여러 개의 스크린을 가진 독립적인 네비게이터가 필요해. 이런 걸 Nested navigation이라도 함.
GetX를 적극적으로 써보려는 생각에 Navigator들도 전부 GetX를 활용해보려고 했는데 나처럼 Bottom Tab navigator와 또 그 안에 Tab별로 navigator가 있는 중첩된(nested) navigator는 GetX로는 힘들다고 그러더라고. 그래서 보통의 방식을 사용했어.
MainNavigator는 Scaffold Body에 Stack으로 중첩된 Navigator들을 가지고 있고 bottomNavigationBar에 BottomTabNavigator를 가지고 있는 구조야.👇
//MainNavigator.dart
import 'package:flutter/material.dart';
import 'BottomTabNavigator.dart';
import 'NavigationTree.dart';
import 'package:get/get.dart';
class MainNavigator extends StatelessWidget {
const MainNavigator({super.key});
@override
Widget build(BuildContext context) {
IndexController indexController = Get.put(IndexController());
return Scaffold(
body: Stack(
children: [
_buildOffstageNavigator(TabItem.home),
_buildOffstageNavigator(TabItem.explore),
_buildOffstageNavigator(TabItem.notice),
_buildOffstageNavigator(TabItem.profile),
],
),
bottomNavigationBar: BottomTabNavigator(),
);
}
}
Widget _buildOffstageNavigator(TabItem tabItem) {
IndexController indexController = Get.find();
return Obx(() => Offstage(
offstage: indexController.currentIndex.value != tabItem,//선택한 탭만 보이도록
child: bottomTabs[tabItem],//각 tab의 네비게이터가 들어 있는 List
));
}
BottomTabNabigator에서 Tab이 선택되면 indexController(GetxController)에 currentIndex로 저장이 되는데 이걸 Offstage 위젯에 사용해 선택된 tab의 Navigator만 보이게 하는거지.
BottomTabNavigator 은 특별한 건 없어. GetX IndexController가 있다는 것 정도? 그런데 컨트롤로도 별도로 파일을 만들어서 옮길거니까 뭐 ㅎㅎㅎ Tab 설정한 거 빼고는 없다고 봐야지.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'NavigationTree.dart';
class IndexController extends GetxController {
static IndexController get to => Get.find();
var currentIndex = TabItem.home.obs;
void changeTabIndex(TabItem index) => currentIndex.value = index;
}
class BottomTabNavigator extends StatelessWidget {
const BottomTabNavigator({super.key});
@override
Widget build(BuildContext context) {
IndexController indexController = Get.find();//GetxController
return Obx(() => BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
_buildItem(TabItem.home),
_buildItem(TabItem.explore),
_buildItem(TabItem.notice),
_buildItem(TabItem.profile),
],
currentIndex: bottomTabs[indexController.currentIndex.value]!.index,
onTap: (index) =>
indexController.changeTabIndex(TabItem.values[index]),//Get update
));
}
BottomNavigationBarItem _buildItem(TabItem tabItem) {
return BottomNavigationBarItem(
icon: Icon(bottomTabs[tabItem]!.icon),
label: bottomTabs[tabItem]!.name,
);
}
}
그런데 가만보면 전부 bottomTabs라는 List에서 정보나 위젯을 가져오는데 이건 NavigationTree.dart라는 파일에 const로 선언된 List야. 음... 나는 파일 하나에서 전체 네비게이션 트리가 관리되도록 하고 하고 싶었거든 ㅎㅎ 👇
//NavigationTree.dart
import 'package:flutter/material.dart';
import 'package:socialchart/screens/ScreenLogin.dart';
import 'package:socialchart/screens/ScreenSignin.dart';
//Tab navigator
import 'TabNavigator.dart';
//Screens
import 'package:socialchart/screens/ScreenHome.dart';
import 'package:socialchart/screens/ScreenExplore.dart';
import 'package:socialchart/screens/ScreenNotice.dart';
import 'package:socialchart/screens/ScreenProfile.dart';
import 'package:socialchart/screens/ScreenChart.dart';
import 'package:socialchart/screens/ScreenInsightCard.dart';
enum TabItem { home, explore, notice, profile }
class ScreenRoute {
const ScreenRoute({required this.path, required this.screen});
final String path;
final Widget screen;
}
class BottomTab extends StatelessWidget {
const BottomTab({
required this.name,
required this.icon,
required this.index,
required this.routes,
});
final String name;
final IconData icon;
final int index;
final List<ScreenRoute> routes;
// final Widget? widget;
@override
Widget build(BuildContext context) {
return TabNavigator(
routes: routes,
);
}
}
const Map<TabItem, BottomTab?> bottomTabs = {
TabItem.home: BottomTab(
name: "홈",
icon: Icons.home,
index: 0,
routes: [
ScreenRoute(path: '/', screen: ScreenHome()),
ScreenRoute(path: '/ScreenHome', screen: ScreenHome()),
ScreenRoute(path: '/ScreenInsightCard', screen: ScreenInsightCard()),
ScreenRoute(path: '/ScreenChart', screen: ScreenChart()),
],
),
TabItem.explore: BottomTab(
name: "탐색",
icon: Icons.search,
index: 1,
routes: [
ScreenRoute(path: '/', screen: ScreenExplore()),
ScreenRoute(path: '/ScreenExplore', screen: ScreenExplore()),
],
),
TabItem.notice: BottomTab(
name: "알림",
icon: Icons.notifications_none,
index: 2,
routes: [
ScreenRoute(path: '/', screen: ScreenNotice()),
ScreenRoute(path: '/ScreenNotice', screen: ScreenNotice()),
],
),
TabItem.profile: BottomTab(
name: "내정보",
icon: Icons.person,
index: 3,
routes: [
ScreenRoute(path: '/', screen: ScreenProfile()),
ScreenRoute(path: '/ScreenProfile', screen: ScreenProfile()),
],
),
};
const List<ScreenRoute> loginRoutes = [
ScreenRoute(path: '/', screen: ScreenLogin()),
ScreenRoute(path: '/ScreenLogin', screen: ScreenLogin()),
ScreenRoute(path: '/ScreenSignin', screen: ScreenSignin()),
];
여기에 모든 네비게이터 정보가 다 있어. 그래서 뭔가 수정할 때 이 파일 저 파일 왔다갔다 하는 걸 조금 줄여주겠지? 라고 하는 헛된 희망을 가져봤어. 그리고 각 탭의 네비게이터에서 사용될 Screen들을 임시로 만들어줬음. Flutter에서는 Page라는 용어를 사용하는 거 같은데... 난 React Native에서 넘어와서 그런지;;; Screen이 편하더라고 그래서 Screen으로 부름 ㅋㅋ 내 앱임 ㅋ 내 맘임 ㅋ
시험 삼아서 홈 탭과 탐색 탭의 첫 화면으로 둘 다 똑같은 ListView를 Home Screen으로 지정해봤어. 같은 스크린을 사용하더라도 각 네비게이션 안에서는 독립적으로 동작하는 걸 확인할 수가 있어! 로그인 Navigator랑 Screen 까지 어느 정도 됐지만 블로깅은 내일!
10월 14일날 시작해서 지금 딱 1주일 지났어. 사실 한달안에 앱스토어 심사 넣는게 목표였는데 ㅎㅎ 가능할까? ㅎ 안되면 말고! 안녕!
2022.10.22 - [Flutter/Flutter Project] - [소셜차트] 앱 제작기 #4. 로그인 시스템 구성
'Flutter > Flutter Project' 카테고리의 다른 글
[소셜차트] 앱 제작기 #6. Profile & Notice Screen Layout (1) | 2022.10.26 |
---|---|
[소셜차트] 앱 제작기 #5. Model and Firestore 1% (0) | 2022.10.24 |
[소셜차트] 앱 제작기 #4. 로그인 시스템 구성 (0) | 2022.10.22 |
[소셜차트] 앱 제작기 #2. 기본 설정 (0) | 2022.10.14 |
[소셜차트] 앱 제작기 #1. 시작하기 전에! (0) | 2022.10.14 |