Flutter: AppBar Widget ve Özelleştirme
Son güncelleme:
4 dk okuma

AppBar, Scaffold'un appBar parametresine verdiğimiz üst çubuktur. Kullanıcıya hangi ekranda olduğunu söyler, geri dönüş ya da menü butonunu taşır ve o ekrana özel eylemleri (ara, paylaş, sil) sağ tarafta toplar. Tek bir title ile başlarsınız; ekran büyüdükçe leading, actions ve bottom alanları devreye girer. Bu yazıda bu alanları, Material 3 ile gelen renk davranışını ve en sık yapılan hataları sırayla ele alıyorum.
Canlı Demo
Aşağıdaki interaktif örnekte bu widget'ı deneyebilirsiniz:
💡 Eğer yukarıdaki örnek açılmazsa, DartPad linkine tıklayarak yeni sekmede çalıştırabilirsiniz.
Temel Kullanım
Scaffold(
appBar: AppBar(
title: const Text('Sayfa Başlığı'),
),
body: const Center(child: Text('İçerik')),
)AppBar'ı Scaffold'a verdiğinizde durum çubuğu boşluğu, yükseklik ve geri butonu sizin yerinize hesaplanır. Navigator ile açılan bir sayfada geri oku, drawer tanımlı bir Scaffold'da ise menü ikonu kendiliğinden gelir.
Önemli Özellikler
| Özellik | Açıklama |
|---|---|
title |
Başlık widget'ı (genellikle Text) |
leading |
Sol taraftaki widget (geri butonu, menü ikonu) |
actions |
Sağ taraftaki butonlar listesi |
bottom |
Çubuğun altına eklenen alan (TabBar, ilerleme çubuğu) |
backgroundColor |
Arka plan rengi |
foregroundColor |
Başlık ve ikonların rengi |
elevation / shadowColor |
Gölge miktarı ve gölge rengi |
scrolledUnderElevation |
İçerik çubuğun altına kaydığında uygulanan yükseklik |
centerTitle |
Başlığı ortalar |
automaticallyImplyLeading |
Otomatik geri/menü butonunu açar ya da kapatır |
toolbarHeight |
Çubuğun yüksekliği |
Actions Kullanımı
actions bir widget listesidir. İki, en fazla üç ikon koyun; geri kalanını bir taşma menüsüne alın. Bunun için PopupMenuButton biçilmiş kaftandır:
AppBar(
title: const Text('Başlık'),
actions: [
IconButton(
icon: const Icon(Icons.search),
tooltip: 'Ara',
onPressed: () {},
),
PopupMenuButton<String>(
onSelected: (value) {},
itemBuilder: (context) => const [
PopupMenuItem(value: 'settings', child: Text('Ayarlar')),
PopupMenuItem(value: 'help', child: Text('Yardım')),
],
),
],
)tooltip vermeyi atlamayın: uzun basınca açıklama gösterir ve ekran okuyucular butonu bu metinle okur.
Leading Özelleştirme
leading alanını kendiniz doldurursanız otomatik geri ve menü butonu devre dışı kalır; davranışı da siz yazarsınız. Menüyü açmak için Scaffold.of(context) gerekir ve bu çağrının Scaffold'un altındaki bir context ile yapılması şarttır, o yüzden Builder kullanıyoruz:
AppBar(
leading: Builder(
builder: (context) => IconButton(
icon: const Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
title: const Text('Başlık'),
)Bu tuzağın ayrıntısını Drawer yazısında anlattım. İkon yerine "Vazgeç" gibi bir metin butonu koyacaksanız alan dar gelir; leadingWidth ile genişletin.
bottom Alanı
bottom, PreferredSizeWidget bekler; yani yüksekliğini önceden bildiren bir widget. TabBar bu arayüzü zaten uygular, bu yüzden sekmeli ekranlarda doğrudan bottom'a verilir. Kendi widget'ınızı koyacaksanız PreferredSize ile sarın:
AppBar(
title: const Text('Siparişler'),
bottom: const PreferredSize(
preferredSize: Size.fromHeight(4),
child: LinearProgressIndicator(),
),
)Arama Çubuğu ve Gradient
title herhangi bir widget olabildiği için içine TextField koyabilirsiniz. Arka plana gradient vermek için flexibleSpace kullanılır; bu alan çubuğun arkasına çizilir:
AppBar(
title: const Text('Gradient'),
foregroundColor: Colors.white,
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Colors.purple, Colors.blue],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
)Material 3'te Renk ve Gölge
Material 3'te AppBar varsayılan olarak colorScheme.surface renginde ve gölgesizdir. İçerik çubuğun altına kaydığında çubuk "scrolled under" durumuna geçer: scrolledUnderElevation devreye girer ve yüzey rengi bir ton değişir. Flutter sürümüne göre bu, surface tint bindirmesi ya da farklı bir surface tonu olarak görünür. Tasarımınızda çubuk hep aynı renkte kalacaksa bunu tema düzeyinde sabitleyin:
final scheme = ColorScheme.fromSeed(seedColor: Colors.indigo);
ThemeData(
colorScheme: scheme,
appBarTheme: AppBarTheme(
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
scrolledUnderElevation: 0,
surfaceTintColor: Colors.transparent,
),
)AppBarTheme kullanmanın ikinci faydası, her ekranda aynı renkleri tekrar yazmaktan kurtulmaktır.
Ne Zaman Kullanılır, Ne Zaman Kullanılmaz?
Başlığı ve birkaç eylemi olan her standart ekranda AppBar doğru seçimdir. Şu durumlarda başka bir şeye bakın:
- Başlık kaydırmayla küçülecek, büyük bir görsel taşıyacak ya da yukarı kaydırınca geri gelecekse
SliverAppBargerekir. Bunu SliverAppBar ile kategori başlığı ve arama alanı yazısında işledim. - Tam ekran görsel, onboarding ya da video oynatıcı gibi ekranlarda çubuk hiç olmayabilir;
appBarparametresini boş bırakın ve içeriğiSafeAreaile koruyun. - İçerik çubuğun arkasından görünecekse (şeffaf çubuk)
Scaffold'daextendBodyBehindAppBar: trueveripbackgroundColor: Colors.transparentkullanın. - Ana eylem tekse ve ekranın en önemli işiyse onu
actionsiçine gömmek yerineFloatingActionButtonyapın.
Sık Yapılan Hatalar
1. Liste kaydırılınca çubuğun rengi değişiyor. Belirti: sayfa açıldığında çubuk beyaz, liste biraz kayınca grimsi ya da renkli bir ton alıyor. Bu bir hata değil, yukarıda anlattığım Material 3 davranışıdır. İstemiyorsanız backgroundColor değerini açıkça verin ve scrolledUnderElevation: 0 yazın.
2. elevation verdim ama gölge çıkmıyor. Material 3'te varsayılan gölge rengi şeffaftır. Gölge istiyorsanız rengini de söyleyin:
AppBar(
title: const Text('Gölgeli'),
elevation: 4,
shadowColor: Colors.black54,
)3. Arka planı değiştirdim, başlık ve ikonlar okunmuyor. Koyu bir backgroundColor verip yazıyı varsayılan koyu renkte bırakmak çok sık görülür. Text'e tek tek stil vermek yerine foregroundColor kullanın; başlığı, geri okunu ve actions ikonlarını birlikte boyar:
AppBar(
title: const Text('Profil'),
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
)4. Özel leading koyunca geri butonu kayboldu. leading verdiğinizde otomatik buton tamamen devre dışı kalır. Geri davranışını (Navigator.pop(context)) kendiniz yazın ya da yalnızca gerektiği durumda leading verin, diğer durumda null bırakın. Aşağıdaki senaryo tam bunu yapıyor.
Mini Senaryo: Çoklu Seçim Modu
Bir not listesi düşünün. Bir nota uzun basınca seçim modu açılsın: başlık seçili sayıyı göstersin, solda kapatma butonu, sağda silme butonu çıksın. Seçim bitince çubuk eski haline dönsün. Bunun için ikinci bir AppBar yazmaya gerek yok; aynı çubuğun alanlarını duruma göre dolduruyoruz:
class NotesPage extends StatefulWidget {
const NotesPage({super.key});
@override
State<NotesPage> createState() => _NotesPageState();
}
class _NotesPageState extends State<NotesPage> {
final List<String> _notes = List.generate(20, (i) => 'Not ${i + 1}');
final Set<String> _selected = {};
bool get _selectionMode => _selected.isNotEmpty;
void _toggle(String note) {
setState(() {
if (!_selected.remove(note)) _selected.add(note);
});
}
void _deleteSelected() {
setState(() {
_notes.removeWhere(_selected.contains);
_selected.clear();
});
}
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(
backgroundColor: _selectionMode ? scheme.primaryContainer : null,
leading: _selectionMode
? IconButton(
icon: const Icon(Icons.close),
tooltip: 'Seçimi kapat',
onPressed: () => setState(_selected.clear),
)
: null,
title: Text(_selectionMode ? '${_selected.length} seçildi' : 'Notlarım'),
actions: _selectionMode
? [
IconButton(
icon: const Icon(Icons.delete_outline),
tooltip: 'Sil',
onPressed: _deleteSelected,
),
]
: [
IconButton(
icon: const Icon(Icons.search),
tooltip: 'Ara',
onPressed: () {},
),
],
),
body: ListView.builder(
itemCount: _notes.length,
itemBuilder: (context, index) {
final note = _notes[index];
return ListTile(
title: Text(note),
selected: _selected.contains(note),
onLongPress: () => _toggle(note),
onTap: _selectionMode ? () => _toggle(note) : null,
);
},
),
);
}
}Dikkat edilecek iki nokta var. leading seçim modu dışında null kalıyor, böylece bu sayfa Navigator ile açıldığında geri oku kendiliğinden görünmeye devam ediyor. backgroundColor da aynı şekilde null olunca temadaki değere düşüyor; kullanıcı modun değiştiğini renkten anlıyor, siz de iki ayrı çubuk yönetmiyorsunuz.
Sık Sorulan Sorular
AppBar yüksekliği nasıl değiştirilir?
toolbarHeight parametresiyle. bottom alanı kullanıyorsanız onun yüksekliği buna ayrıca eklenir.
Geri butonunu nasıl kaldırırım?
automaticallyImplyLeading: false yazın. Bu yalnızca butonu gizler; Android'in sistem geri hareketi çalışmaya devam eder, onu engellemek için PopScope gerekir.
Tüm ekranlarda aynı AppBar stilini nasıl kullanırım?
ThemeData içindeki appBarTheme alanına bir AppBarTheme verin. Renk, centerTitle, scrolledUnderElevation gibi ayarlar oradan tüm AppBar'lara uygulanır; tek bir ekranda farklı değer gerekiyorsa o AppBar'ın kendi parametresi temayı ezer.
AppBar ile SliverAppBar arasındaki fark nedir?
AppBar sabit yükseklikte durur ve Scaffold'a verilir. SliverAppBar bir CustomScrollView içinde yaşar ve kaydırmaya göre genişleyip daralabilir, gizlenip geri gelebilir.
İlgili Yazılar
Flutter: Card Widget ve Tasarım Kullanımı
Flutter Card rehberi: Material 3 Card.filled ve Card.outlined, resimde clipBehavior, InkWell ile tıklanabilir kart, sık hatalar ve ürün kartı örneği.
Flutter: BottomSheet ve showModalBottomSheet Kullanımı
Flutter'da showModalBottomSheet ile değer döndürmek, isScrollControlled, useSafeArea, showDragHandle, klavye boşluğu, DraggableScrollableSheet ve kalıcı sheet.
Flutter: BottomNavigationBar ve NavigationBar Karşılaştırması
BottomNavigationBar'dan Material 3 NavigationBar'a geçiş: özellik eşleme tablosu, labelBehavior, karar rehberi ve uyarlanabilir kabuk örneği.