Chuyển đến nội dung chính

レッスン 5: ナビゲーションとルーティング

ナビゲーター 2.0、GoRouter。名前付きルート、パスパラメータ、クエリパラメータ。ネストされたナビゲーション、タブ ナビゲーション、ドロワー ナビゲーション。ディープリンク、ルートガード。

💻 プログラミング — レッスン 5 レッスン 5: ナビゲーションとルーティング

フラッター&ダーツ: 基本から上級まで

パート 2: ナビゲーションと状態管理

xdev.asia

1. GoRouter のセットアップ

# pubspec.yaml
dependencies:
  go_router: ^14.0.0
final router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
    ),
    GoRoute(
      path: '/products',
      builder: (context, state) => const ProductListPage(),
      routes: [
        GoRoute(
          path: ':id',
          builder: (context, state) {
            final id = state.pathParameters['id']!;
            return ProductDetailPage(id: id);
          },
        ),
      ],
    ),
    GoRoute(
      path: '/search',
      builder: (context, state) {
        final query = state.uri.queryParameters['q'] ?? '';
        return SearchPage(query: query);
      },
    ),
  ],
  redirect: (context, state) {
    final isLoggedIn = authNotifier.isLoggedIn;
    if (!isLoggedIn && state.matchedLocation.startsWith('/dashboard')) {
      return '/login';
    }
    return null;
  },
);

2. ナビゲーション

// Programmatic navigation
context.go('/products');
context.push('/products/123');
context.pop();

// Named routes
context.goNamed('productDetail', pathParameters: {'id': '123'});

3. シェルルート (タブナビゲーション)

ShellRoute(
  builder: (context, state, child) {
    return MainShell(child: child);
  },
  routes: [
    GoRoute(path: '/home', builder: (_, __) => const HomePage()),
    GoRoute(path: '/explore', builder: (_, __) => const ExplorePage()),
    GoRoute(path: '/profile', builder: (_, __) => const ProfilePage()),
  ],
);

class MainShell extends StatelessWidget {
  final Widget child;
  const MainShell({super.key, required this.child});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: child,
      bottomNavigationBar: NavigationBar(
        selectedIndex: _calculateIndex(GoRouterState.of(context).matchedLocation),
        destinations: const [
          NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
          NavigationDestination(icon: Icon(Icons.explore), label: 'Explore'),
          NavigationDestination(icon: Icon(Icons.person), label: 'Profile'),
        ],
        onDestinationSelected: (index) {
          switch (index) {
            case 0: context.go('/home');
            case 1: context.go('/explore');
            case 2: context.go('/profile');
          }
        },
      ),
    );
  }
}

次の記事: Riverpod による状態管理。