Widget, Flutter çerçevesinin temel kavramıdır ve kullanıcı arayüzü öğesinin yapılandırmasını tanımlar. Bir düğmeden karmaşık animasyona kadar her görsel bileşen bir Widget'tır. UI'nin ayrı XML dosyalarıyla tanımlandığı veya emperatif olarak boyandığı diğer çerçevelerin aksine Flutter, Widget kompozisyonu — küçük bölünmez öğeleri hiyerarşik bir ağaçta birleştirme — yoluyla arayüzü oluşturur. Flutter Dokümantasyonu'na (2025) göre, Flutter SDK kitaplığı Material Design, Cupertino ve özel stilleri kapsayan 260'tan fazla yerleşik Widget içerir.
Önemli Noktalar
Flutter'da bir Widget, kullanıcı arayüzünün bir bölümünün değişmez (immutable) bir tanımıdır. Her Widget yapılandırma özellikleri içerir: boyut, renk, konum, metin, olay işleyicileri ve alt Widget'lar. Widget'lar doğrudan oluşturulmaz — bunlar, Flutter Engine'in ekrandaki gerçek grafik nesnesi olan bir RenderObject oluşturduğu planlardır (blueprint).
Flutter'ın felsefesi şöyledir: “Everything is a Widget”. Bu, yalnızca görünür öğelerin (Text, Image, Button) değil, aynı zamanda yapısal blokların (Padding, Center, Column, Stack), davranışsal blokların (GestureDetector, AnimatedBuilder) ve hatta uygulamanın kendisinin (MaterialApp, CupertinoApp) de Widget olduğu anlamına gelir. Bu yaklaşım tekdüzelik sağlar: herhangi bir ekran öğesi, basit yerleştirme yoluyla başka herhangi bir öğeyle birleştirilebilir.
Google I/O 2024 — Flutter Widgets Deep Dive'a göre, ortalama bir Flutter uygulaması herhangi bir anda 200 ila 1500 Widget içerir. Bu miktara rağmen Flutter, C++ Skia/Impeller motoru düzeyindeki optimizasyonlar sayesinde düşük bütçeli cihazlarda bile 60 FPS korur. Widget'lar hafif nesnelerdir (her biri 40–80 bayt), bu nedenle oluşturulmaları bir performans darboğazı değildir.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Merhaba, Flutter!'),
),
),
);
}
}
Widget'ın nasıl çalıştığını anlamak için, birbirine bağlı üç ağaçtan oluşan Flutter mimarisini anlamak gerekir. Birincisi — Widget ağacı — UI yapılandırmasını tanımlar. Her karede tamamen yeniden oluşturulabilen hafif bir ağaçtır (çöp toplayıcı eski Widget'ları kaldırır ve yenilerini oluşturur). Widget'lar değişmezdir (immutable): metin rengi değişirse, yeni renkle yeni bir Text Widget oluşturulur, eskisi atılır.
İkinci ağaç — Element ağacı — Widget ve RenderObject arasındaki bağlantıdır. Element, Widget (yapılandırma) ve RenderObject (oluşturma) için bir referans içerir. Bir Widget değiştiğinde, Flutter yeni Widget'ı eski Element ile karşılaştırır ve karar verir: mevcut RenderObject'u güncelle (Widget aynı türdeyse) veya yeni bir tane oluştur (Widget türü değiştiyse). Bu sürece Reconciliation denir ve React Virtual DOM'a benzer.
Üçüncü ağaç — RenderObject ağacı — ekrandaki gerçek oluşturmadan sorumludur. RenderObject, belirli boyutlar, konumlar ve boyama yöntemleri içerir. Flutter Engine (C++ Skia veya Impeller), RenderObject ağacını dolaşır ve her düğümü oluşturur. RenderObject ağacı en ağır ağaçtır, bu nedenle Flutter, aynı türdeki Widget'lara geçerken RenderObject'ları yeniden kullanarak değişikliklerini en aza indirir.
| Ağaç | Amaç | Değişmez? | Yaşam Döngüsü |
|---|---|---|---|
| Widget | UI Yapılandırması (plan) | Evet | Her build'te yeniden oluşturulur |
| Element | Widget ↔ RenderObject bağlantısı | Hayır | Widget ağaçta olduğu sürece var olur |
| RenderObject | Oluşturma ve düzen | Hayır | Ağır, mümkünse yeniden kullanılır |
Flutter, Widget'ları iki temel türe ayırır: StatelessWidget ve StatefulWidget. StatelessWidget, değiştirilebilir durum içermeyen bir widget'tır. StatelessWidget'ın görünümü tamamen yapıcısı tarafından belirlenir ve oluşturulduktan sonra değişemez. Örnekler: Text, Icon, Divider, Padding. StatelessWidget'ın tüm özellikleri yapıcıda final olarak bildirilir ve salt okunurdur.
StatefulWidget, değiştirilebilir duruma sahip bir widget'tır. İki sınıftan oluşur: Widget'ın kendisi (StatelessWidget gibi değişmez yapılandırma) ve State (değiştirilebilir durum). Widget'ı State'den ayırmak, Flutter'da önemli bir mimari karardır. Her build'te Widget yeniden oluşturulur, ancak State nesnesi, ağaçtaki widget'ın tüm yaşam döngüsü boyunca varlığını sürdürerek durumunu korur.
setState() çağrıldığında, Flutter State'i “kirli” olarak işaretler ve sonraki karede alt ağacı yeniden oluşturmak için build() yöntemini çağırır. Önemli: setState() Widget'ın kendisini yeniden oluşturmaz — yalnızca mevcut State'te build() çağrısını tetikler. Bu, StatefulWidget'ın, alt öğelerin anahtarları (Key) sabit kaldığı sürece, alt Widget'ların durumunu kaybetmeden UI'yı güncelleyebileceği anlamına gelir.
// StatelessWidget — görünüm asla değişmez
class GreetingWidget extends StatelessWidget {
const GreetingWidget({super.key, required this.name});
final String name;
@override
Widget build(BuildContext context) {
return Text('Merhaba, $name');
}
}
// StatefulWidget — değiştirilebilir durumlu sayaç
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Sayı: $_count'),
ElevatedButton(
onPressed: () => setState(() => _count++),
child: const Text('Artır'),
),
],
);
}
}
Flutter'daki tüm Widget'lar işlevsel amaca göre üç ana kategoriye ayrılabilir. Layout Widget'ları — alt öğelerin ekranda konumlandırılmasından sorumludur. Row ve Column çocukları bir satıra dizer, Stack birini diğerinin üzerine yerleştirir, Expanded ve Flexible mevcut alanı dağıtır. Layout Widget'larının kendi görsel temsilleri yoktur — alt widget'ların konumunu ve boyutunu yönetirler.
Painting Widget'ları — görsel stil oluşturmadan sorumludur. Container, dekorasyonları (renk, gradyan, gölge, kenarlık) düzen özellikleriyle birleştirir. Padding boşluk ekler, DecoratedBox arka plan çizer, Transform dönüşümler (döndürme, ölçekleme) uygular. Painting Widget'ları, görsel stilin yapı taşlarıdır ve istenen görünümü elde etmek için genellikle Layout Widget'larıyla birlikte kullanılır.
Interactive Widget'ları — kullanıcı girişini işler. GestureDetector jestleri (dokunma, kaydırma, sıkıştırma) algılar, InkWell Material dalga efekti ekler, TextField metin girişini kabul eder, Slider ve Switch standart kontrol öğeleri sağlar. Interactive Widget'lar, yapıcıya iletilen veya durum sağlayıcıları aracılığıyla işlenen geri çağırma işlevleri aracılığıyla olayları yükseltir.
| Kategori | Widget Örnekleri | Amaç |
|---|---|---|
| Layout | Row, Column, Stack, Expanded, Flexible, Align | Alt öğelerin konumlandırılması ve boyutlandırılması |
| Painting | Container, Padding, DecoratedBox, RotatedBox | Renk, arka plan, kenarlıklar, gölgeler, dönüşümler |
| Interactive | GestureDetector, InkWell, TextField, Slider | Dokunma, giriş, jest işleme |
| Platform | MaterialApp, CupertinoApp, Theme, MediaQuery | Platform entegrasyonu, temalar, uyarlama |
| Async | FutureBuilder, StreamBuilder, ValueListenableBuilder | Zaman uyumsuz verilerden reaktif güncelleme |
Flutter Widget of the Week (Google, 2025)'e göre, Flutter topluluğu neredeyse her arayüzü oluşturmak için layout + painting + interactive Widget kombinasyonunu aktif olarak kullanır. Örneğin, bir düğme: InkWell (interactive) + Container (painting) + Text (static) + Padding (layout). Bu modülerlik, kod tekrarı olmadan farklı bağlamlarda standart blokların yeniden kullanılmasına olanak tanır.
Widget kompozisyonu, bazı Widget'ları diğerlerinin içine yerleştirerek UI oluşturma sürecidir. Alt sınıfın ebeveynin davranışını devraldığı klasik kalıtımın (extends) aksine, Flutter toplamayı kullanır: her Widget, child parametresi (bir için) veya children (birkaç için) aracılığıyla diğer Widget'ları içerir. Bu yaklaşım daha fazla esneklik ve yeniden kullanılabilirlik sağlar.
BuildContext, Widget'tan sonraki en önemli ikinci kavramdır. BuildContext, öğe ağacında bir Widget'ın konumunun bir tanımlayıcısıdır. BuildContext aracılığıyla bir Widget, ata widget'lara (Theme.of(context), MediaQuery.of(context), Navigator.of(context)) erişebilir. BuildContext, build() yöntemine iletilir ve ebeveyn ve alt öğelerle etkileşim için kullanılır. Her Widget'ın tam olarak bir BuildContext'i vardır ve bu, ağaçtaki konumunu benzersiz şekilde tanımlar.
Flutter Architectural Overview (Google, 2025)'e göre BuildContext, InheritedWidget'ın temelidir — yapıcılar aracılığıyla açık aktarım olmadan ağaçta aşağı doğru veri aktarmaya izin veren bir mekanizma. Theme, MediaQuery, Navigator ve Provider dahili olarak InheritedWidget'ı kullanır. Derinlemesine yerleştirilmiş herhangi bir Widget, BuildContext.dependOnInheritedWidgetOfExactType aracılığıyla ata verilerine erişebilir, bu da BuildContext'i Flutter'ın reaktif mimarisinin anahtarı yapar.
// Widget kompozisyonu yerleştirme yoluyla
Scaffold(
appBar: AppBar(title: const Text('Benim Uygulamam')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Flutter'a Hoş Geldiniz',
style: TextStyle(fontSize: 24)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () { /* nav */ },
child: const Text('Başla'),
),
],
),
),
)
// BuildContext ile temalara erişim
Text(
'Stilize Metin',
style: Theme.of(context).textTheme.headlineMedium,
)
İlk ve en yaygın hata, StatelessWidget'ın yeterli olduğu yerde StatefulWidget kullanmaktır. Birçok acemi Flutter geliştiricisi, durum harici bir sağlayıcıda (Provider, Riverpod, BLoC) saklansa bile tüm widget'lar için StatefulWidget oluşturur. Bu aşırıdır ve performansı düşürür. Kural: durum harici olarak yönetiliyorsa veya widget'ın kendi değiştirilebilir durumu yoksa StatelessWidget kullanın.
İkinci hata — const yapıcı olmadan build yöntemi içinde Widget oluşturmaktır. const olmadan oluşturulan her Widget, her build'te yeniden tahsis edilir. build() içinde const yapıcıyla Widget'lar oluşturursanız, Flutter aynı örneği yeniden kullanabilir ve çöp toplayıcının yükünü azaltabilir. Mümkün olan her yerde const ekleyin — özellikle Text, Icon, SizedBox, Padding ve diğer durumsuz Widget'lar için.
Üçüncü hata — anahtarlarla (Key) yanlış çalışmaktır. Flutter, ağacı yeniden oluştururken Widget'ları tanımlamak için Key kullanır. Bir Widget listesi Key olmadan yeniden oluşturulursa, Flutter öğelerin sırasını karıştırabilir, bu da yanlış animasyona veya durum kaybına yol açar. Listelerdeki öğeler için her zaman bir Key (örneğin ValueKey veya ObjectKey) ekleyin, özellikle dinamik verilerle ListView.builder kullanırken.
Sıkça Sorulan Sorular
StatelessWidget — değiştirilebilir durumu olmayan widget, görünümü tamamen yapıcı tarafından belirlenir. StatefulWidget — değiştirilebilir duruma sahip widget, ayrı bir State nesnesinde saklanır ve widget'ı yeniden oluşturmadan setState() aracılığıyla güncellenebilir. Mümkün olduğunda StatelessWidget, yerel durum gerektiğinde StatefulWidget kullanın.
Widget'ların değişmezliği, performans için Flutter'ın mimari kararıdır. Widget'lar değişebilir olsaydı, Flutter her build'te eski ve yeni yapılandırmaları güvenli bir şekilde karşılaştıramazdı. Değişmezlik, Flutter'ın bir Widget'ın değişip değişmediğini (== operatörü aracılığıyla) hızlıca belirlemesine ve mevcut RenderObject'u yeniden kullanarak pahalı oluşturma işlemlerini en aza indirmesine olanak tanır.
BuildContext, öğe ağacında bir Widget'ın konumunun bir tanımlayıcısıdır. Bu sayede Widget, ata widget'lara (Theme, MediaQuery, Navigator) ve InheritedWidget'a erişim sağlar. BuildContext ayrıca gezinme (Navigator.of(context)), SnackBar gösterme ve Provider ile etkileşim için kullanılır. Her Widget, build() yöntemi aracılığıyla BuildContext alır ve onu alt öğelere iletir.
Öğelerin yatay düzeni için Row, dikey düzen için Column, öğeleri üst üste yerleştirmek için Stack kullanın. Row ve Column flexbox prensibine göre çalışır: çocuklar mainAxisSize, mainAxisAlignment ve crossAxisAlignment'a göre yer kaplar. Stack, kenarlara veya merkeze göre hassas konumlandırma için konumlandırılmış çocuklar kullanır.
Flutter, üç mekanizma aracılığıyla yüksek performans elde eder: (1) Widget'lar ucuzdur — hafif değişmez nesneler (40–80 bayt), oluşturulmaları GC'yi yüklemez. (2) RenderObject yeniden kullanımı — aynı türdeki Widget'a geçerken RenderObject yeniden kullanılır, pahalı yeniden oluşturmayı önler. (3) Skia/Impeller motoru — yeniden boyama sınırları aracılığıyla en aza indirilmiş çizim çağrılarıyla C++ düzeyinde oluşturma.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun