전 포스팅에서는 GoRouter 를 이용해 navigation Bar 을 구현하는 방법에 대해 알아보았습니다.
이번 포스팅에서는 ShellRoute를 응용하여 프로젝트에 적용해보는 과정을 담아보겠습니다.
개발하고자 하는 구현 목표는 아래에 네비게이션 바였습니다. 처음 구현을 하고자 할 때 궁금한 점은 다음과 같았습니다.
ShellRoute
는 GoRouter 라우팅 시스템 내에서 중첩된 라우팅을 구현하기 위한 클래스입니다. ShellRoute
를 사용하면 애플리케이션의 주요 부분(예: 탭 바, 드로어)을 공통 UI 셸로 유지하면서 내부 컨텐츠를 독립된 Navigator
로 관리할 수 있습니다. 기본 문법은 다음과 같습니다:
ShellRoute(
routes: [
GoRoute(
path: '/somePath',
builder: (context, state) => SomeWidget(),
),
// 추가 라우트...
],
)
애플리케이션에서 모든 페이지가 기본 페이지('/')를 거치도록 구성하려면, initialLocation
속성을 사용하여 GoRouter를 설정할 때 기본 경로를 지정할 수 있습니다. 예를 들어, 모든 페이지 요청이 '/' 경로를 거쳐 이동하도록 설정하려면 다음과 같이 구현할 수 있습니다:
final goRouter = GoRouter(
initialLocation: '/',
routes: [
ShellRoute(
path: '/',
builder: (context, state, child) => BasePage(child: child),
routes: [
GoRoute(
path: 'todo',
builder: (context, state) => TodoPage(),
),
// 추가 라우트...
],
),
],
);
예제에서는 창의 상태를 저장하였지만, 실제 프로젝트에서는 상태를 저장하지 않고 페이지를 이동합니다. 이때는 StatefulShellRoute 가 아닌 ShellRoute 를 사용해야 합니다.
ShellRoute(
navigatorKey: _shellNavigatorKey,
builder: (context, state, child) =>
BottomNavigationBarScaffold(child: child),
routes: [
GoRoute(
path: 'todo',
pageBuilder: (context, state) =>
const NoTransitionPage(child: ToDoPage())),
GoRoute(
path: 'board',
pageBuilder: (context, state) => const NoTransitionPage(
child: TeamsListScreen(),
)),
GoRoute(
path: 'my',
pageBuilder: (context, state) => const NoTransitionPage(
child: MyPage(),
)),
],
),
프로젝트에 적용하는 과정은 다음과 같았습니다.
class BottomNavigationBarScaffold extends StatefulWidget {
const BottomNavigationBarScaffold({Key? key, required this.child})
: super(key: key);
final Widget child;
@override
State<BottomNavigationBarScaffold> createState() =>
_BottomNavigationBarScaffoldState();
}
class _BottomNavigationBarScaffoldState
extends State<BottomNavigationBarScaffold> {
int selectedIndex = 0;
void onDestinationSelected(int index) {
setState(() {
selectedIndex = index;
});
switch (index) {
case 0:
context.go('/todo');
break;
case 1:
context.go('/board');
break;
case 2:
context.go('/my');
// 추가 탭이 있다면 여기에 구현
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: widget.child,
// bottomNavigationBar: BottomNavigationBar(
// onTap: changeTab,
// currentIndex: currentIndex,
// items: const [
// BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
// BottomNavigationBarItem(icon: Icon(Icons.chat), label: 'Chat'),
// // 추가 탭이 있다면 여기에 아이템 추가
// ],
// ),
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
destinations: const [
NavigationDestination(label: 'Todo', icon: Icon(Icons.check_circle)),
NavigationDestination(label: 'Board', icon: Icon(Icons.dashboard)),
NavigationDestination(label: 'My', icon: Icon(Icons.person)),
],
onDestinationSelected: onDestinationSelected,
),
);
}
}
final _shellNavigatorKey = GlobalKey<NavigatorState>();
final router = GoRouter(initialLocation: '/', routes: [
GoRoute(path: '/', builder: (context, state) => const HomeScreen(), routes: [
GoRoute(
path: 'example',
name: 'example',
builder: (context, state) => const FormDemoScreen2(),
),
GoRoute(
path: 'login',
name: 'login',
builder: (context, state) => const LoginScreen(),
),
GoRoute(
path: 'signup',
name: 'signup',
builder: (context, state) => const SignInScreen(),
),
GoRoute(
path: 'emailSignup',
name: 'emailSignup',
builder: (context, state) => const EmailSignInScreen(),
),
GoRoute(
path: 'teamsList',
name: 'teamsList',
builder: (context, state) => const TeamsListScreen(),
),
GoRoute(
path: 'teamCreate',
name: 'teamCreate',
builder: (context, state) => const TeamCreateScreen(),
),
GoRoute(
path: 'teamDetail',
name: 'teamDetail',
builder: (context, state) => TeamDetailScreen(),
),
GoRoute(
path: 'projectDetail',
name: 'projectDetail',
builder: (context, state) => const ProjectDetailScreen(),
),
GoRoute(
path: 'projectCreation',
name: 'projectCreation',
builder: (context, state) => ProjectCreationScreen(),
),
GoRoute(
path: 'projectUpdate',
name: 'projectUpdate',
builder: (context, state) => ProjectUpdateScreen(),
),
GoRoute(
path: 'main',
name: 'main',
builder: (context, state) => const MainScreen(),
),
ShellRoute(
navigatorKey: _shellNavigatorKey,
builder: (context, state, child) =>
BottomNavigationBarScaffold(child: child),
routes: [
GoRoute(
path: 'todo',
pageBuilder: (context, state) =>
const NoTransitionPage(child: ToDoPage())),
GoRoute(
path: 'board',
pageBuilder: (context, state) => const NoTransitionPage(
child: TeamsListScreen(),
)),
GoRoute(
path: 'my',
pageBuilder: (context, state) => const NoTransitionPage(
child: MyPage(),
)),
],
),
]),
]);
잘 봤습니다. 여기서 다시 뵈니 반갑네요.