Flutter'da Navigation 2.0 ve GoRouter ile Sayfa Yönetimi
Flutter'ın Navigator 1.0 API'si basit uygulamalar için yeterliydi; ancak deep link, web URL desteği ve karmaşık navigasyon yapıları için Navigation 2.0 gereklidir. GoRouter bu karmaşıklığı sezgisel bir API ile yönetir.
Kurulum
// pubspec.yaml: go_router: ^14.2.0
Temel Rota Tanımı
import 'package:go_router/go_router.dart';
final router = GoRouter(
initialLocation: "/",
routes: [
GoRoute(
path: "/",
builder: (context, state) => const AnaSayfa(),
),
GoRoute(
path: "/blog",
builder: (context, state) => const BlogListesi(),
routes: [
GoRoute(
path: ":id", // /blog/42
builder: (context, state) {
final id = state.pathParameters["id"]!;
return BlogDetay(id: id);
},
),
],
),
GoRoute(
path: "/profil/:kullaniciId",
builder: (context, state) {
final kullaniciId = state.pathParameters["kullaniciId"]!;
final sekme = state.uri.queryParameters["sekme"] ?? "yazılar";
return ProfilSayfasi(kullaniciId: kullaniciId, sekme: sekme);
},
),
],
);
// main.dart
MaterialApp.router(
routerConfig: router,
title: "Uygulamam",
)
Programatik Navigasyon
// Sayfaya git
context.go("/blog");
// Parametre ile
context.go("/blog/42");
// Query parametresi ile
context.go("/profil/user123?sekme=favoriler");
// Stack'e push (geri dönülebilir)
context.push("/blog/42");
// Veri döndüren push
final sonuc = await context.push<bool>("/onay-diyalogu");
if (sonuc == true) {
// onaylandı
}
// Geri
context.pop();
context.pop(true); // değerle geri
Rota Koruması (Auth Guard)
final router = GoRouter(
initialLocation: "/",
redirect: (context, state) {
final auth = context.read<AuthProvider>();
final girisYapildi = auth.girisYapildi;
final girisYolunda = state.matchedLocation == "/giris";
if (!girisYapildi && !girisYolunda) return "/giris";
if (girisYapildi && girisYolunda) return "/";
return null; // yönlendirme yok
},
refreshListenable: authProvider, // auth değişince router yeniden değerlendirir
routes: [
GoRoute(path: "/giris", builder: (_, __) => const GirisSayfasi()),
GoRoute(path: "/", builder: (_, __) => const AnaSayfa()),
GoRoute(
path: "/admin",
redirect: (context, state) {
final auth = context.read<AuthProvider>();
return auth.adminMi ? null : "/";
},
builder: (_, __) => const AdminPaneli(),
),
],
);
ShellRoute ile Alt Navigasyon (Bottom Navbar)
final router = GoRouter(
routes: [
ShellRoute(
builder: (context, state, child) => AnaYerlesim(child: child),
routes: [
GoRoute(path: "/", builder: (_, __) => const AnaSayfa()),
GoRoute(path: "/kesfet", builder: (_, __) => const KesfetSayfasi()),
GoRoute(path: "/profil", builder: (_, __) => const ProfilSayfasi()),
],
),
],
);
class AnaYerlesim extends StatelessWidget {
final Widget child;
const AnaYerlesim({super.key, required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: NavigationBar(
selectedIndex: _seciliIndeks(context),
onDestinationSelected: (i) => _sayfayaGit(context, i),
destinations: const [
NavigationDestination(icon: Icon(Icons.home), label: "Ana Sayfa"),
NavigationDestination(icon: Icon(Icons.explore), label: "Keşfet"),
NavigationDestination(icon: Icon(Icons.person), label: "Profil"),
],
),
);
}
int _seciliIndeks(BuildContext context) {
final konum = GoRouterState.of(context).matchedLocation;
if (konum.startsWith("/kesfet")) return 1;
if (konum.startsWith("/profil")) return 2;
return 0;
}
void _sayfayaGit(BuildContext context, int index) {
switch (index) {
case 0: context.go("/");
case 1: context.go("/kesfet");
case 2: context.go("/profil");
}
}
}
Özel Geçiş Animasyonu
GoRoute(
path: "/detay/:id",
pageBuilder: (context, state) => CustomTransitionPage(
key: state.pageKey,
child: DetaySayfasi(id: state.pathParameters["id"]!),
transitionsBuilder: (context, animation, secondary, child) =>
FadeTransition(opacity: animation, child: child),
transitionDuration: const Duration(milliseconds: 300),
),
)
Deep Link Testi
# Android — adb ile test
adb shell am start -a android.intent.action.VIEW \
-d "myapp://blog/42" \
com.example.uygulamam
# AndroidManifest.xml
# <intent-filter>
# <action android:name="android.intent.action.VIEW" />
# <data android:scheme="myapp" android:host="blog" />
# </intent-filter>
Sonuç
GoRouter, Flutter'ın Navigation 2.0 karmaşıklığını zarif bir şekilde soyutlar. Rota koruması, nested navigation ve deep link desteğiyle büyük uygulamalarda bile navigasyon katmanını yönetilebilir tutar. ShellRoute ile bottom navigation bar entegrasyonu ise tek sayfada birden fazla gezinme ağacını mümkün kılar.