저번 글에서 auto_route
를 이용한 Flutter 의 화면 routing 을 알아보았다. 이전 시간에 알아 본 내용만으로도 auto_route
의 사용함에 충분한 이유가 될 수 있지만 그 밖에 auto_route
를 더 강력하게 만들어 주는 기능들을 알아보자.
Tab Navigation 은 모바일에서 가장 자주 쓰이는 형태의 화면 구성이다. 각 Tab 별로 화면 스택이 별도로 이루어지며, Tab 이동시 이전 Tab 의 화면 스택 히스토리도 유지되어야 한다. 이를 구현하기는 자체 구현하는것은 이거저거 신경쓸게 많아서 골치가 아프다. 하지만 auto_route
는 이를 쉽고 직관적으로 사용할 수 있도록 도와준다.
auto_route
에서 사용되는 모든 화면 route 정보는 appRouter 를 통해 한다고 했었다. 그럼 Tab Navigation 과 같은 Nested Navigation 은 어떻게 설정해야 할까.
간단히 children 프로퍼티 통해 nested 될 화면들을 전달해주면 된다.
(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(
page: HomePage,
initial: true,
children: [
AutoRoute(page: BookFeedPage),
AutoRoute(page: BookListPage),
AutoRoute(page: MyInfoPage)
]
),
AutoRoute(path:' /login', page: LoginPage)
]
)
class $AppRouter {}
children 프로퍼티 통해 화면들을 리스트로 전달해 주었다. 물론 nested 의 nested 된 구성도 가능하다. 하지만 모바일 UI 에서 그렇게 까지 구성하는것은은 좋은 방식이 아니라고 생각된다.
이제 routing 설정이 끝났으니 실제 화면에서 Tab 을 구현해 보자.
구현은 AutoTabsRouter
를 이용해서 구현할 수 있다.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return AutoTabsRouter(
routes: const [
BookFeedRoute(),
BookListRoute(),
MyInfoRoute()
],
builder: (context, child, animation) {
final tabRouter = AutoTabsRouter.of(context);
return Scaffold(
body: FadeTransition(
opacity: animation,
child: child,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: tabRouter.activeIndex,
onTap: (index) {
tabRouter.setActiveIndex(index);
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.feed), label: 'book feed'),
BottomNavigationBarItem(icon: Icon(Icons.book), label: 'book list'),
BottomNavigationBarItem(icon: Icon(Icons.man), label: 'my info'),
],
),
);
}
);
}
}
AutoTabsRouter
를 통해 route 정보를 등록하였고, UI 로 구성은 builder 를 통해 구현하였다.
만약 위 코드 보다 좀 더 간단하게 구현하고 싶다면 AutoTabsScaffold
을 이용한다면 좀 더 간결한 코드를 작성할 수 있다.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return AutoTabsScaffold(
routes: const [
BookFeedRoute(),
BookListRoute(),
MyInfoRoute()
],
bottomNavigationBuilder: (_, tabsRouter) {
return BottomNavigationBar(
currentIndex: tabsRouter.activeIndex,
onTap: tabsRouter.setActiveIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.feed), label: 'book feed'),
BottomNavigationBarItem(icon: Icon(Icons.book), label: 'book list'),
BottomNavigationBarItem(icon: Icon(Icons.man), label: 'my info'),
]
);
},
);
}
}
만약 특정 화면에서 로그인 여부에 따라 화면 제한을 걸고 싶을 때 RouteGuard
를 사용할 수 있다.
RouteGuard
는 일종의 middleware 또는 interceptor 라고 생각하면 된다. 화면 진입시 권한 체크를 통해 로그인 화면으로 이동시켜줄 수 있고, 로그인 결과에 따라 화면 이동 여부를 결정 해 줄 수 있다
class AuthGuard extends AutoRouteGuard {
void onNavigation(NavigationResolver resolver, StackRouter router) {
if(authenitcated){
// 접근 권한이 있다면 화면 이동
resolver.next(true);
}else{
// 접근 권한이 없다면 로그인 화면으로 이동 시킨다
router.push(LoginRoute(onResult: (success){
// 로그인 화면에서의 결과에 따라 화면 이동 여부를 결정
resolver.next(success);
}));
}
}
}
위에 작성한 Guard 를 my_info.dart 화면에 연결시켜주기 위해서는 아래와 같이 설정하면 된다.
(
replaceInRouteName: 'Page,Route',
routes: <AutoRoute>[
AutoRoute(
page: HomePage,
initial: true,
children: [
AutoRoute(page: BookFeedPage),
AutoRoute(page: BookListPage),
AutoRoute(page: MyInfoPage, guards: [AuthGuard]) // Guard 추가
]
),
AutoRoute(path:' /login', page: LoginPage)
]
)
class $AppRouter {}
복수의 guard 를 등록하고 싶다면 list 안에 추가적으로 추가하면 된다.
observer
는 화면 이동이 일어날 때 그 변화를 추적할 수 있다. AutoRouterObserver
를 이용해서 구현 할 수 있다.
class RouteObserver extends AutoRouteObserver{
// 화면이 push 될 때
void didPush(Route route, Route? previousRoute) {
print('New route pushed: ${route.settings.name}');
}
// Tab router 가 초기화 될 때
void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) {
print('Tab route visited: ${route.name}');
}
// Tab 이동이 일어날 때
void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) {
print('Tab route re-visited: ${route.name}');
}
}
작성된 Observer 는 main.dart 의 router 설정하는 부분에서 해 줄 수 있다. navigatorObservers
는 list 형태로 반환되며, 복수의 Observer 를 등록할 수 있다.
return MaterialApp.router(
routerDelegate: AutoRouterDelegate(
_appRouter,
navigatorObservers: () => [RouteObserver()],
),
routeInformationParser: _appRouter.defaultRouteParser(),
);
지금까지 Auto_route
에 대해 알아보았다. 모바일 개발에서 routing 은 매우 중요한 부분 중에 하나다. 사실 다른건 다 몰라도 tab 구현과 guard 를 이용한 화면 관리는 매우 유용하게 쓰일 수 있을꺼 같다. 앱 개발시 초반에 화면 routing 에 대한 규칙을 정하고 미리 뼈대를 잡아 둘 수 있다면 프로젝트 수행이 한결 편해질 것이다.