Flutter: Padding ile İç Boşluk Yönetimi
Son güncelleme:
5 dk okuma

Padding, çocuğunun etrafında boş alan bırakan tek işli bir widget'tır: aldığı kısıtlamalardan EdgeInsets değerini düşer, çocuğu kalan alanda ölçer ve onu belirtilen kadar içeri kaydırır. Bir kart içeriğinin kenarlara yapışmaması, bir liste satırının nefes alması, bir sayfanın ekran kenarından 16 piksel uzak durması hep bu widget'ın işidir. Bu yazıda EdgeInsets'in tüm kurucularını, RTL diller için EdgeInsetsDirectional'ı, SafeArea ve klavye boşluklarıyla ilişkisini ve konsolda en sık gördüğünüz hataları anlatıyorum.
Temel Kullanım
Padding(
padding: const EdgeInsets.all(16),
child: Text('Etrafımda 16 piksel boşluk var'),
)Flutter'ın Padding widget'ı API dokümanında da vurgulandığı gibi Padding'in kendisi görünmezdir; arka plan rengi yoktur, dokunma alanı eklemez. Yalnızca çocuğuna verilen alanı daraltır ve çocuğu kaydırır. Bu yüzden "boşluk nerede kaldı?" diye bakarken Flutter Inspector'da Padding'i seçip mavi taralı alanı görmek en hızlı yoldur.
EdgeInsets Kurucuları
Boşluk değerleri EdgeInsets sınıfıyla verilir. Dört kurucu ve bir sabit vardır; hangisini seçtiğiniz okunabilirlik meselesidir, sonuç aynıdır.
// Dört kenar eşit
const EdgeInsets.all(16)
// Yatay (sol+sağ) ve dikey (üst+alt) ayrı
const EdgeInsets.symmetric(horizontal: 16, vertical: 8)
// Sadece belirttiğiniz kenarlar; diğerleri 0
const EdgeInsets.only(left: 16, top: 8)
// Sol, üst, sağ, alt sırasıyla (Left, Top, Right, Bottom)
const EdgeInsets.fromLTRB(16, 8, 16, 12)
// Hiç boşluk yok
EdgeInsets.zeroDeğerler sabitse const yazın; widget ağacı her build'de yeni bir EdgeInsets nesnesi oluşturmaz. fromLTRB dört sayıyı yan yana yazdığı için okunması en zor olanıdır; üç veya dört farklı değer gerekiyorsa bile only ile isimlendirilmiş parametreleri tercih edin.
EdgeInsetsDirectional: Sağdan Sola Diller
left ve right fiziksel yönlerdir. Arapça veya İbranice gibi sağdan sola (RTL) yazılan bir dilde uygulamanız açıldığında, "metnin başında 16 piksel boşluk" demek istiyorsanız left yanlış kenarı seçer. EdgeInsetsDirectional sınıfının API dokümanının anlattığı gibi EdgeInsetsDirectional, start ve end kavramlarıyla çalışır ve Directionality'ye göre kendini çevirir:
Padding(
padding: const EdgeInsetsDirectional.only(start: 16, end: 8),
child: Text('LTR\'de solda 16, RTL\'de sağda 16'),
)EdgeInsetsDirectional.all, .symmetric ve .fromSTEB (Start, Top, End, Bottom) kurucuları da vardır. Uygulamanız yalnızca Türkçe ise fiziksel EdgeInsets yeterlidir; ama çok dilli bir uygulamada yatay boşluğun asimetrik olduğu her yerde Directional sürümü kullanmak sonradan yeniden yazmaktan kurtarır.
Padding, Container(padding) ve SizedBox
Üç ayrı araç boşlukla ilgilidir ve karıştırılır:
Padding: Tek bir çocuğun etrafında boşluk. En hafif seçenek.Container(padding: ...): Container zaten renk, kenarlık veya köşe yuvarlatma için oradaysapaddingparametresini kullanın. Container bunu arka planda zaten birPaddingwidget'ına çevirir; ayrı bir Padding sarmalamak iş görür ama gereksiz iç içelik yaratır.SizedBox(height: 16): İki kardeş widget arasındaki boşluk. Column içinde iki metin arasına mesafe koymak için Padding değil SizedBox kullanın; Padding çocuğun etrafını sarar, kardeşler arası bir "ayraç" değildir. Ayrıntısı SizedBox yazısında.
Bir de margin vardır: Container'ın margin parametresi dış boşluktur, yani arka plan rengi boşluktan sonra başlar. padding ise iç boşluktur, arka plan rengi boşluğu da kaplar. Görsel farkı en net gösteren şey renkli bir Container ile denemektir.
SafeArea ve Sistem Boşlukları
Çentik, durum çubuğu ve alt navigasyon çubuğu ekranın bir kısmını kapatır. SafeArea, bu bölgeler kadar padding ekleyen özel bir widget'tır:
Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [Text('Güvenli alanda')]),
),
),
)Sistemin ne kadar yer kapladığını kendiniz okumak isterseniz MediaQuery.paddingOf(context) size bir EdgeInsets verir; örneğin MediaQuery.paddingOf(context).bottom alt navigasyon çubuğunun yüksekliğidir. Klavyenin kapladığı alan ise MediaQuery.viewInsetsOf(context).bottom ile okunur. Genellikle Scaffold resizeToAvoidBottomInset sayesinde bunu sizin için halleder; ama Scaffold dışında özel bir alt panel yapıyorsanız bu değeri padding'e eklemeniz gerekir. Ekran ölçülerini MediaQuery ile okumanın detaylarını MediaQuery yazısında bulabilirsiniz.
Ne Zaman Kullanılır, Ne Zaman Kullanılmaz?
Padding'e uzanın:
- Tek bir widget'ın içeriğini kenarlardan uzaklaştırmak istediğinizde.
- Sayfa gövdesini ekran kenarından ayırırken (
EdgeInsets.all(16)veyasymmetric(horizontal: 16)). - Kart, liste satırı, dialog gibi kapsayıcıların iç boşluğunda.
Padding kullanmayın:
- Kardeşler arası mesafe için:
SizedBox(ya da güncel Flutter sürümlerinde Row ve Column'unspacingparametresi) daha temizdir. - ListView'ın kenar boşluğu için:
ListView(padding: ...)kullanın. ListView'ı dışarıdan Padding ile sararsanız kaydırma alanı da daralır; öğeler kenarların altına kaymak yerine sert bir çizgide kesilir. - Buton içi boşluk için:
ElevatedButton.styleFrom(padding: ...)gibi stil parametreleri butonun dokunma alanını da büyütür; dışarıdan sarılan Padding büyütmez. - Negatif boşluk için:
EdgeInsetsnegatif değer kabul etmez. Çocuğu dışarı taşırmak içinTransform.translateveyaOverflowBoxkullanın.
Sık Yapılan Hatalar
1. Dar kutuda padding çocuğu ezer
Belirti: Sabit genişlikli bir kutuya padding eklediniz, içerideki metin sarıldı veya ikon küçüldü. Padding kendi boyutunu büyütmez; aldığı alandan boşluğu düşer ve çocuğa kalanı verir. 100 piksellik bir SizedBox içinde EdgeInsets.all(20) çocuğa 60 piksel bırakır.
// Çocuk 60 piksel genişlik alır
SizedBox(
width: 100,
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('Uzun bir metin sarılır'),
),
)Çözüm: Kutuyu padding kadar büyütün ya da padding'i kutunun dışına alın.
2. Row içinde uzun metne padding vermek
Belirti: A RenderFlex overflowed by 42 pixels on the right. Row, çocuklarına sınırsız genişlik verir; Padding de bunu metne aktarır, metin tek satırda uzar ve taşar.
Row(
children: [
const Icon(Icons.info),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: Text('Bu metin artık kalan alanda sarılır'),
),
),
],
)Padding'i Expanded içine almak sorunu çözer; Expanded'ın neden gerektiğini Expanded yazısında anlattım.
3. Negatif değer vermek
Belirti: Uygulama debug modda 'padding.isNonNegative': is not true assertion hatasıyla çöker. EdgeInsets negatif olamaz; niyetiniz çocuğu kaydırmaksa Transform.translate(offset: Offset(-10, 0)) kullanın.
4. SafeArea'yı ListView'ın dışına koymak
Belirti: Liste kaydırılınca öğeler durum çubuğunun altına doğal biçimde girmiyor, üstte sert bir boşluk kalıyor. ListView, padding verilmediğinde kaydırma ekseninde sistem boşluklarını zaten kendisi uygular; dışına sardığınız SafeArea ise listeyi küçültür. Çözüm: SafeArea'yı kaldırın ve ya padding'i boş bırakın ya da ListView(padding: MediaQuery.paddingOf(context)) gibi kendi değerinizi verin. Öğeler kaydırılırken çentiğin altına girer, ilk öğe ise yine güvenli alanda başlar.
Mini Senaryo: Giriş Formu
Bir giriş ekranı düşünün: içerik ekran kenarından 24 piksel uzak, alanlar arasında 16 piksel, buton kaydırma sırasında klavyeye yapışmasın.
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Giriş yap', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 24),
const TextField(
decoration: InputDecoration(
labelText: 'E-posta',
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
const TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Şifre',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 24),
FilledButton(
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
onPressed: () {},
child: const Text('Giriş Yap'),
),
],
),
),
),
);
}
}Üç farklı boşluk aracı bir arada: SingleChildScrollView.padding sayfa kenarlarını ayarlar ve kaydırma alanına dahil olur; SizedBox alanlar arasındaki mesafeyi verir; contentPadding ve FilledButton.styleFrom(padding:) ise bileşenlerin kendi iç boşluğudur ve dokunma alanını büyütür. SafeArea çentiği, Scaffold ise klavyeyi halleder. Form doğrulama tarafını Form widget yazısında ayrıca anlattım.
Sık Sorulan Sorular
Padding ile margin arasındaki fark nedir?
Padding iç boşluktur: widget'ın arka planı boşluğu da kaplar. Margin dış boşluktur: arka plan boşluktan sonra başlar. Flutter'da ayrı bir Margin widget'ı yoktur; Container'ın margin parametresi aslında dıştan sarılmış bir Padding'dir.
Container padding mi, Padding widget mı daha performanslı?
İkisi aynı işi yapar; Container padding verildiğinde içeride bir Padding widget'ı oluşturur. Yalnızca boşluk gerekiyorsa Padding daha az widget üretir; Container zaten renk veya kenarlık için oradaysa padding parametresini kullanın.
EdgeInsets neden negatif değer almıyor?
Padding çocuğa kalan alanı verir; negatif bir değer çocuğa aldığından fazla alan vermek anlamına gelir ve layout modeliyle çelişir. Çocuğu dışarı kaydırmak için Transform.translate, taşmasına izin vermek için OverflowBox kullanın.
Sağdan sola dillerde padding nasıl doğru çalışır?
left/right yerine EdgeInsetsDirectional'ın start/end parametrelerini kullanın. Widget, üstteki Directionality'ye göre başlangıç kenarını otomatik seçer; yalnızca simetrik yatay boşluklarda fark yoktur.
İlgili Yazılar
Flutter: MediaQuery ile Ekrana Göre Oranlama
MediaQuery.sizeOf, paddingOf ve textScalerOf ile ekrana göre boyutlama; ne zaman LayoutBuilder veya FractionallySizedBox daha doğru olur ve sık yapılan hatalar.
Flutter: Stack ve Positioned ile Üst Üste Yerleşim
Flutter Stack ve Positioned rehberi: Stack'in boyutu, fit, alignment, clipBehavior, Positioned.fill, PositionedDirectional, rozet ve katman tarifleri, hatalar.
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.