Flutter'da Navigator ile Sayfalar Arası Geçiş ve Veri Transferi
Sayfalar Arası Geçiş - Navigator Kullanımı
İlk defa sayfalar arası geçiş yapmaya çalıştığımda biraz kafam karıştı. "Web'de link varken Flutter'da nasıl oluyor bu iş?" diye düşünmüştüm. Sonra Navigator'ı keşfettim ve her şey netleşti.
Flutter'da sayfalar arası geçiş yapmak için Navigator sınıfı kullanılır. Bir çeşit yığın (stack) yapısı gibi çalışır: Sayfa açarsınız üste eklenir, geri tuşuna basarsınız üstteki sayfa çıkar.
Canlı Demo: Navigator Kullanımı
Sayfalar arası geçiş ve veri transferini interaktif olarak deneyin:
Temel Navigator Kullanımı
En basit haliyle bir sayfadan diğerine geçiş:
// Ana sayfa
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Ana Sayfa')),
body: Center(
child: ElevatedButton(
child: Text('Detay Sayfasına Git'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailPage()),
);
},
),
),
);
}
}
// Detay sayfası
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Detay Sayfa')),
body: Center(
child: Text('Bu detay sayfası'),
),
);
}
}Navigator.push() yeni bir sayfa açar. MaterialPageRoute sayfa geçiş animasyonunu sağlar.
Geri Dönüş - pop()
Geri dönmek için iki yol var:
1. Otomatik Geri Tuşu
AppBar kullanırsanız Flutter otomatik olarak geri tuşu ekler. Kullanıcı buna tıklayınca geri döner.
2. Kod ile Geri Dönüş
ElevatedButton(
child: Text('Geri Dön'),
onPressed: () {
Navigator.pop(context);
},
)Navigator.pop() üstteki sayfayı stack'ten çıkarır.
Sayfalar Arası Veri Gönderme
Asıl güzellik buradan başlıyor. Sayfaya veri göndermek için constructor kullanıyoruz.
Veri Gönderen Sayfa
class ProductListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Ürünler')),
body: ListView(
children: [
ListTile(
title: Text('iPhone 15'),
subtitle: Text('50.000 TL'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
productName: 'iPhone 15',
price: 50000,
description: 'Yeni nesil akıllı telefon',
),
),
);
},
),
ListTile(
title: Text('Samsung S24'),
subtitle: Text('45.000 TL'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
productName: 'Samsung S24',
price: 45000,
description: 'Android\'in en iyisi',
),
),
);
},
),
],
),
);
}
}Veri Alan Sayfa
class ProductDetailPage extends StatelessWidget {
final String productName;
final int price;
final String description;
const ProductDetailPage({
Key? key,
required this.productName,
required this.price,
required this.description,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(productName)),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
productName,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'${price.toString()} TL',
style: TextStyle(fontSize: 20, color: Colors.green),
),
SizedBox(height: 16),
Text(
description,
style: TextStyle(fontSize: 16),
),
],
),
),
);
}
}Constructor'da required ile parametreleri zorunlu kılıyoruz. Böylece sayfa açılırken mutlaka bu bilgiler verilmeli.
Geri Dönerken Veri Döndürme
Bazen açtığınız sayfadan veri almak istersiniz. Mesela kullanıcı bir şey seçti, bu seçimi önceki sayfaya göndermek istiyorsunuz.
Veri İsteyen Sayfa
class SelectCityPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Şehir Seç')),
body: Center(
child: ElevatedButton(
child: Text('Şehir Seç'),
onPressed: () async {
// Sayfa aç ve sonuç bekle
final selectedCity = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => CityListPage()),
);
// Sonuç geldi
if (selectedCity != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Seçilen: $selectedCity')),
);
}
},
),
),
);
}
}Veri Döndüren Sayfa
class CityListPage extends StatelessWidget {
final List<String> cities = [
'İstanbul',
'Ankara',
'İzmir',
'Antalya',
'Bursa',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Şehir Listesi')),
body: ListView.builder(
itemCount: cities.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(cities[index]),
onTap: () {
// Seçilen şehri geri gönder
Navigator.pop(context, cities[index]);
},
);
},
),
);
}
}Navigator.pop(context, deger) ile ikinci parametre olarak veri gönderiyoruz.
pushReplacement - Geri Dönüşü Engelleme
Bazen kullanıcının geri tuşu ile önceki sayfaya dönmesini istemezsiniz. Tipik örnek: Giriş yaptıktan sonra login sayfasına geri dönülmesin.
push() ile Normal Geçiş
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
// Kullanıcı geri tuşuna basarsa login sayfasına dönerpushReplacement() ile Geçiş
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
// Geri tuşu stack'teki bir önceki sayfaya gider, login atlanırPratik Örnek: Login Sonrası
class LoginPage extends StatelessWidget {
void _login(BuildContext context) {
// Login işlemi başarılı
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text('Giriş Yap'),
onPressed: () => _login(context),
),
),
);
}
}Artık HomePage'deyken geri tuşuna basarsa LoginPage'e dönmez, uygulamadan çıkar.
Kayıt Sonrası Örnek
class RegisterPage extends StatelessWidget {
void _register(BuildContext context) {
// Kayıt işlemi başarılı
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => LoginPage()),
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Kayıt başarılı! Giriş yapabilirsiniz.')),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Kayıt Ol')),
body: Center(
child: ElevatedButton(
child: Text('Kaydı Tamamla'),
onPressed: () => _register(context),
),
),
);
}
}pushAndRemoveUntil - Tüm Stack'i Temizleme
Bazen sadece bir sayfayı değil, tüm stack'i temizlemek istersiniz.
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => HomePage()),
(route) => false, // Tüm sayfaları kaldır
);Bu, kullanıcıyı tamamen yeni bir akışa yönlendirmek için kullanılır. Örneğin çıkış yapınca tüm sayfalar temizlenir, sadece login ekranı kalır.
Çıkış Yapma Örneği
void logout(BuildContext context) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => LoginPage()),
(route) => false,
);
}Named Routes (İsimlendirilmiş Rotalar)
Daha büyük projelerde her seferinde MaterialPageRoute yazmak zahmetli. İsimlendirilmiş rotalar kullanabilirsiniz.
main.dart'ta Rota Tanımlama
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/detail': (context) => DetailPage(),
'/profile': (context) => ProfilePage(),
'/settings': (context) => SettingsPage(),
},
);
}
}İsimlendirilmiş Rota ile Geçiş
// Normal geçiş
Navigator.pushNamed(context, '/detail');
// Geri dönüşü engelleme
Navigator.pushReplacementNamed(context, '/home');
// Stack temizleme
Navigator.pushNamedAndRemoveUntil(
context,
'/login',
(route) => false,
);İsimlendirilmiş Rotada Veri Gönderme
// Veri gönderme
Navigator.pushNamed(
context,
'/detail',
arguments: {
'id': 123,
'name': 'Ahmet',
},
);
// Veri alma
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map;
return Scaffold(
appBar: AppBar(title: Text(args['name'])),
body: Center(
child: Text('ID: ${args['id']}'),
),
);
}
}Navigation ile Animasyon
Farklı geçiş animasyonları ekleyebilirsiniz:
Sağdan Sola Kayma (Varsayılan)
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailPage()),
);Aşağıdan Yukarı
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailPage(),
fullscreenDialog: true,
),
);Özel Animasyon
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => DetailPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.easeInOut;
var tween = Tween(begin: begin, end: end).chain(
CurveTween(curve: curve),
);
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
),
);Geri Tuşunu Yakalamak
Android'de geri tuşuna basıldığında özel işlem yapmak:
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// Kullanıcıya sor
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('Çıkmak istediğinize emin misiniz?'),
actions: [
TextButton(
child: Text('Hayır'),
onPressed: () => Navigator.pop(context, false),
),
TextButton(
child: Text('Evet'),
onPressed: () => Navigator.pop(context, true),
),
],
),
);
return shouldPop ?? false;
},
child: Scaffold(
appBar: AppBar(title: Text('Sayfa')),
body: Center(child: Text('İçerik')),
),
);
}
}Pratik İpuçları
1. Context'i Doğru Kullanın
// ❌ Yanlış - build context kullanımı
Navigator.push(context, ...);
// ✅ Doğru - doğru context
Builder(
builder: (BuildContext context) {
return ElevatedButton(
onPressed: () => Navigator.push(context, ...),
child: Text('Git'),
);
},
)2. Async/Await Kullanımı
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectPage()),
);
if (result != null) {
print('Sonuç: $result');
}3. Gereksiz Navigator Kullanımından Kaçının
// ❌ Gereksiz - aynı sayfa içinde
Navigator.push(context, MaterialPageRoute(...));
// ✅ State güncellemesi kullanın
setState(() {
selectedIndex = 1;
});Özet
Flutter'da Navigation:
- push(): Yeni sayfa aç
- pop(): Geri dön
- pushReplacement(): Geri dönüşü engelle
- pushAndRemoveUntil(): Stack'i temizle
- pushNamed(): İsimli rota kullan
Veri Transferi:
- Constructor ile ileri veri gönder
pop(context, veri)ile geri veri döndür
Back Stack Yönetimi:
- Login/Register sonrası
pushReplacementkullan - Çıkış yaparken
pushAndRemoveUntilile stack'i temizle
Navigator, Flutter'ın en temel özelliklerinden. Bir kere alıştıktan sonra çok rahat kullanıyorsunuz!
Navigation konusunda takıldınız mı?
Bir sonraki yazıda görüşmek üzere! 🚀