Loading...
Loading...
Flutter 프로젝트의 라우팅 패턴 — `go_router` 기반 경로 선언, `RoutePaths` 상수 관리, `StatefulShellRoute`로 바텀 내비게이션 구현, 경로 파라미터(`:recipeId`) 처리, `context.go`/`context.push` 사용. "라우트 추가", "go_router", "화면 이동", "네비게이션", "GoRoute", "StatefulShellRoute", "pathParameters", "딥링크" 같은 표현에 트리거합니다.
npx skill4agent add junsuk5/survival-flutter-skills flutter-navigation-go-routerlib/core/routing/route_paths.dartRoutePathslib/core/routing/router.dartGoRouterroutermain.dartMaterialApp.routercontext.gocontext.pushRoutePaths// lib/core/routing/route_paths.dart
abstract class RoutePaths {
static const String splash = '/Splash';
static const String signIn = '/SingIn';
static const String signUp = '/SingUp';
static const String home = '/Home';
static const String savedRecipes = '/SavedRecipes';
static const String notifications = '/Notifications';
static const String profile = '/Profile';
static const String search = '/Home/Search';
static const String ingredient = '/Home/Ingredient/:recipeId';
}/<Name>/Home/Ingredient/:recipeId:name// lib/core/routing/router.dart
final router = GoRouter(
initialLocation: RoutePaths.splash,
routes: [
GoRoute(
path: RoutePaths.ingredient,
builder: (context, state) {
final recipeId = int.parse(state.pathParameters['recipeId']!);
return IngredientRoot(recipeId: recipeId);
},
),
GoRoute(
path: RoutePaths.splash,
builder: (context, state) => SplashScreen(
onTapStartCooking: () => context.go(RoutePaths.signIn),
),
),
// ... 기타 라우트
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) => MainScreen(
body: navigationShell,
currentPageIndex: navigationShell.currentIndex,
onChangeIndex: (index) => navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
),
),
branches: [
StatefulShellBranch(routes: [
GoRoute(path: RoutePaths.home, builder: (c, s) => const HomeRoot()),
]),
StatefulShellBranch(routes: [
GoRoute(path: RoutePaths.savedRecipes, builder: (c, s) => const SavedRecipesRoot()),
]),
// notifications, profile ...
],
),
],
);// lib/main.dart
return MaterialApp.router(
routerConfig: router,
// ...
);state.pathParametersGoRoute(
path: RoutePaths.ingredient, // '/Home/Ingredient/:recipeId'
builder: (context, state) {
final recipeId = int.parse(state.pathParameters['recipeId']!);
return IngredientRoot(recipeId: recipeId);
},
),class IngredientRoot extends StatelessWidget {
final int recipeId;
const IngredientRoot({super.key, required this.recipeId});
}IngredientRootgetIt<IngredientViewModel>()loadRecipe(recipeId)context.gocontext.pushcontext.go(path)context.push(path)// 교체: splash → sign in
context.go(RoutePaths.signIn);
// 푸시: 레시피 상세로 진입
context.push('/Home/Ingredient/${recipe.id}');saved_recipes_root.dartonAction: (action) {
if (action is OnTapRecipe) {
context.push('/Home/Ingredient/${action.recipe.id}');
return;
}
viewModel.onAction(action);
},context.pushStatefulShellRoute.indexedStacknavigationShell.goBranch(index, initialLocation: ...)initialLocation: index == currentIndexStatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) => MainScreen(
body: navigationShell,
currentPageIndex: navigationShell.currentIndex,
onChangeIndex: (index) => navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
),
),
branches: [ /* 탭마다 StatefulShellBranch */ ],
)SplashScreenSignInScreenSignUpScreenGoRoute(
path: RoutePaths.signUp,
builder: (context, state) => SignUpScreen(
onTapSignIn: () => context.go(RoutePaths.signIn),
),
),go_routerRoutePathsrouter.dartStatefulShellBranchGoRoutecontext.gocontext.pushRoutePathsonTap...RoutePathscontext.go(...)BuildContextgo_routerNavigator.of(context).push(MaterialPageRoute(...))go_routerstate.pathParameters['id']!int.parse(state.pathParameters['recipeId']!)