Flutter'a Giriş: Widget Ağacı, Row, Column ve Stack Yapıları
Son güncelleme:
4 dk okuma

Bugün tarihi bir gün! Dart'ın temellerini öğrendikten sonra sonunda Flutter'a geçiş yaptım. Kurulum adımlarını Flutter'a başlangıç rehberinde bulabilirsiniz; bu yazıda doğrudan koda giriyorum. İlk izlenimim: Widget'lar, widget'lar, her yer widget!
Canlı Demo: Row, Column ve Stack Örnekleri
Flutter'ın temel layout yapılarını interaktif olarak deneyin:
💡 Eğer yukarıdaki örnek açılmazsa, DartPad linkine tıklayarak yeni sekmede çalıştırabilirsiniz.
Flutter'ın Yapısını Anlamak
Flutter projesinde ilk dikkatimi çeken şey şu oldu: Her şey bir ağaç yapısı gibi. Main fonksiyonundan başlıyor, sonra uygulama widget'ı, sonra sayfa, sonra scaffold... İç içe geçmiş bir yapı.
Temel Flutter Yapısı
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp()); // Uygulama buradan başlıyor
}main() fonksiyonu her şeyin başladığı yer. runApp() diyerek uygulamamızı başlatıyoruz.
Ana Widget (MyApp)
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'İlk Uygulama',
debugShowCheckedModeBanner: false, // Debug yazısını kaldır
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'İlk Projem'),
);
}
}MaterialApp Flutter'da material design kurallarına göre uygulama yapmanızı sağlıyor. home parametresi ilk açılacak sayfayı belirtiyor.
Sayfa Widget'ı (MyHomePage)
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}StatefulWidget durumu değişebilen widget'lar için. Mesela bir buton sayacı yapıyorsanız, sayı değiştiğinde ekranın güncellenmesi gerekir. İşte bunun için StatefulWidget kullanılır.
State Sınıfı
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
print("Sayfa yüklendi!");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Text("Merhaba Flutter!"),
),
);
}
}initState() sayfa ilk açıldığında bir kere çalışır. API çağrıları genelde buraya yazılır. initState, build ve dispose'un hangi sırayla çalıştığını Flutter yaşam döngüsü yazısında anlattım.
Scaffold bir sayfa iskeletidir. AppBar (üst çubuk), body (içerik), bottomNavigationBar gibi kısımları var.
Flutter'ın Ağaç Yapısı
Flutter'ı anlamanın anahtarı bu ağaç yapısını kavramak:
Main
└─ MyApp (MaterialApp)
└─ MyHomePage (Scaffold)
├─ AppBar
└─ Body
└─ Widget'lar...Her şey iç içe. Şöyle düşünün: Bir bina var (MaterialApp), binanın odaları var (Scaffold), odaların içinde mobilyalar var (Widget'lar).
Tasarım Düzeni: Row, Column ve Stack
Flutter'da layout (yerleşim) için üç temel yapı var. Başta hangisini ne zaman kullanacağımı karıştırıyordum.
Row - Yatay Yerleşim
Row widget'ları yan yana dizer. Soldan sağa.
Row(
children: [
Container(width: 80, height: 80, color: Colors.blue),
Container(width: 80, height: 80, color: Colors.red),
Container(width: 80, height: 80, color: Colors.yellow),
],
)Ekran çıktısı: 🟦🟥🟨 (yan yana üç kare)
Column - Dikey Yerleşim
Column widget'ları alt alta dizer. Yukarıdan aşağıya.
Column(
children: [
Container(width: 80, height: 80, color: Colors.blue),
Container(width: 80, height: 80, color: Colors.red),
Container(width: 80, height: 80, color: Colors.yellow),
],
)Ekran çıktısı:
🟦
🟥
🟨(alt alta üç kare)
Stack - Üst Üste Yerleşim
Stack widget'ları üst üste koyar. Katmanlar gibi.
Stack(
children: [
Container(width: 130, height: 100, color: Colors.blue),
Container(width: 80, height: 70, color: Colors.red),
Container(width: 30, height: 60, color: Colors.yellow),
],
)Büyük mavi kutu altta, orta kırmızı ortada, küçük sarı üstte. Hepsi sol üst köşeden hizalanmış.
Row ve Column Kombinasyonu
Şimdi daha karmaşık bir layout yapalım. Satır ve sütunları birleştirerek:
Hedef: 2 satır, her satırda 4 sütun (toplam 8 kutu)
Column(
children: [
// Birinci satır
Row(
children: [
Container(width: 80, height: 80, color: Colors.yellow),
Container(width: 80, height: 80, color: Colors.red),
Container(width: 80, height: 80, color: Colors.green),
Container(width: 80, height: 80, color: Colors.blue),
],
),
// İkinci satır
Row(
children: [
Container(width: 80, height: 80, color: Colors.red),
Container(width: 80, height: 80, color: Colors.blue),
Container(width: 80, height: 80, color: Colors.yellow),
Container(width: 80, height: 80, color: Colors.green),
],
),
],
)Sonuç:
🟨 🟥 🟩 🟦
🟥 🟦 🟨 🟩Mantığı şöyle: Ana yapı Column (dikey). İçinde iki Row var (yatay). Her Row'un içinde dört Container var.
Container Widget'ı
Container Flutter'ın en temel widget'larından biri. Bir kutu gibi düşünün.
Basit Container
Container(
width: 100,
height: 100,
color: Colors.blue,
child: Text("Merhaba"),
)İçeriği Ortalamak
Container(
width: 100,
height: 100,
color: Colors.blue,
child: Center(
child: Text(
"Merhaba",
style: TextStyle(color: Colors.white),
),
),
)Center widget'ı içindeki şeyi ortalar; detayları Center widget yazısında var.
Margin ve Padding
Container(
width: 100,
height: 100,
margin: EdgeInsets.all(10), // Dıştan boşluk
padding: EdgeInsets.all(20), // İçten boşluk
color: Colors.blue,
child: Text("Merhaba"),
)- Margin: Container'ın dışındaki boşluk
- Padding: Container'ın içindeki boşluk
Sadece iç boşluk gerekiyorsa Container yerine doğrudan Padding widget'ını kullanmak daha hafif bir çözüm.
Köşeleri Yuvarlama
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Text("Yuvarlak"),
),
)decoration kullandığınızda color parametresini decoration içine yazmalısınız.
Border (Kenarlık) Eklemek
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.blue,
width: 3,
),
),
child: Center(
child: Text("Kenarlıklı"),
),
)Row ve Column'da Hizalama
Widget'ları istediğimiz yere hizalayabiliriz:
MainAxisAlignment
Row(
mainAxisAlignment: MainAxisAlignment.center, // Ortala
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 50, height: 50, color: Colors.blue),
],
)Row için mainAxis yataydır. Seçenekler:
start: Sola yaslaend: Sağa yaslacenter: OrtalaspaceBetween: Araya eşit boşlukspaceAround: Etraflarına eşit boşlukspaceEvenly: Her tarafa eşit boşluk
CrossAxisAlignment
Row(
crossAxisAlignment: CrossAxisAlignment.center, // Dikeyde ortala
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 50, height: 100, color: Colors.blue),
],
)Row için crossAxis dikeydir. Seçenekler:
start: Üste yaslaend: Alta yaslacenter: Ortalastretch: Genişlet
Hizalamanın çalışması için Row'un ne kadar yer kapladığı da önemli; mainAxisSize ile bu ilişkiyi mainAxisSize ve hizalama yazısında ayrıntılı ele aldım.
Pratik Örnek: Hesap Makinesi Layout'u
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Ekran
Container(
width: double.infinity,
height: 100,
color: Colors.grey[300],
child: Center(
child: Text(
"0",
style: TextStyle(fontSize: 48),
),
),
),
// Tuşlar
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
butonOlustur("7"),
butonOlustur("8"),
butonOlustur("9"),
butonOlustur("/"),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
butonOlustur("4"),
butonOlustur("5"),
butonOlustur("6"),
butonOlustur("*"),
],
),
],
)İlk Gün Çıkarımlarım
- Flutter'da her şey widget
- Row yatay, Column dikey, Stack üst üste
- Container en çok kullanacağım widget
- MainAxisAlignment ve CrossAxisAlignment ile hizalama yapılıyor
- Scaffold bir sayfa iskeletidir
Yarın buton tıklama, state yönetimi ve dinamik içerik konularına bakacağım. Bu Flutter yolculuğu gerçekten heyecan verici!
Faydalı Kaynaklar
Benimle Flutter öğrenmek ister misiniz?
Flutter öğrenmeye devam! 🚀
Sık Sorulan Sorular
Row içindeki widget'lar ekrana sığmazsa ne olur?
Ekranın kenarında sarı-siyah çizgili bir "overflow" şeridi ve konsolda "A RenderFlex overflowed" uyarısı görürsünüz. Çözüm, taşan çocukları Expanded veya Flexible ile sarmak ya da içeriğin kaydırılması gerekiyorsa Row'u bir SingleChildScrollView içine almaktır.
StatelessWidget ile StatefulWidget'ı nasıl seçerim?
Widget yalnızca dışarıdan aldığı parametreleri gösteriyorsa StatelessWidget yeterlidir. Kullanıcı etkileşimi ya da gelen veriyle ekranın yeniden çizilmesi gerekiyorsa (sayaç, form, yükleniyor durumu) StatefulWidget kullanın.
Her kutu için Container kullanmak zorunda mıyım?
Hayır. Yalnızca boşluk için Padding, yalnızca boyut için SizedBox, yalnızca ortalamak için Center daha hafiftir. Container'ı renk, kenarlık veya köşe yuvarlama gibi bir decoration gerektiğinde tercih edin.
İlgili Yazılar
Flutter: Spacer Widget ile Esnek Boşluklar
Spacer'ın içinde ne olduğu, flex ile boşluk oranlama, SizedBox ve mainAxisAlignment ile farkı, kaydırılabilir alanlarda neden hata verdiği ve çözümü.
Flutter: mainAxisSize ile Alan ve Hizalama Kontrolü
mainAxisSize'ın max ve min farkı, kısıtlarla ilişkisi, mainAxisAlignment'ın neden etkisiz kaldığı ve dialog, bottom sheet, buton grubu tarifleri.
Flutter: Expanded Widget ile Alan Genişletme
Expanded'ın derinlemesine incelemesi: flex oranı nasıl hesaplanır, iç içe kullanım, Row ve Column dışında neden çalışmaz ve en sık görülen üç hata.