Flutter TextField Rehberi: Validasyon, Stil ve İleri Seviye Özellikler

TextField, kullanıcının metin girmesine olanak tanıyan temel bir input bileşenidir. Ancak işin içine girdiğimizde, sadece bir kutudan ibaret olmadığını; doğrulama, stil ve kullanıcı deneyimi (UX) için onlarca parametre barındırdığını görüyoruz.


📌 Flutter TextField ve Özellikleri

Kullanıcıdan Metin Alma Rehberi (Detaylı Anlatım)

Flutter’da kullanıcıdan veri almak, formlar oluşturmak ve etkileşimli arayüzler tasarlamak için en temel yapı taşlarından biri TextField widget’ıdır. Giriş alanları; kullanıcı adı, şifre, arama kutusu, yorum alanı gibi pek çok senaryoda kullanılır.

Bu makalede TextField’ı:

  • Temel kullanımıyla

  • Görsel özelleştirmeleriyle

  • Davranış (event) yönetimiyle

  • Form ve validasyon mantığıyla

detaylı şekilde inceleyeceğiz.


1️⃣ TextField Nedir?

TextField, kullanıcıdan tek satır veya çok satırlı metin girişi almak için kullanılan bir Flutter widget’ıdır.

📌 Özellikleri:

  • Klavye türü belirlenebilir

  • Metin biçimi kontrol edilebilir

  • Anlık değişimler yakalanabilir

  • Tamamen özelleştirilebilir


2️⃣ En Temel TextField Kullanımı

TextField(),

Bu haliyle:

  • Boş bir giriş alanı oluşturur

  • Herhangi bir kontrol veya stil içermez

📌 Genellikle bu kullanım yetersizdir, mutlaka özellik eklenir.


3️⃣ TextField İçine Açıklama (hintText) Ekleme

TextField(
  decoration: InputDecoration(
    hintText: "Adınızı giriniz",
  ),
),

🔹 hintText: Kullanıcı yazmaya başlamadan önce görünen açıklama metni


4️⃣ Label ve Border Kullanımı

TextField(
  decoration: InputDecoration(
    labelText: "E-posta",
    border: OutlineInputBorder(),
  ),
),

📌 Bu kullanım:

  • Daha profesyonel

  • Material Design uyumlu

  • Formlar için idealdir


5️⃣ İkon Ekleme (Prefix & Suffix)

TextField(
  decoration: InputDecoration(
    labelText: "Kullanıcı Adı",
    prefixIcon: Icon(Icons.person),
    suffixIcon: Icon(Icons.check),
  ),
),

🔹 prefixIcon: Başta ikon
🔹 suffixIcon: Sonda ikon


6️⃣ TextEditingController Kullanımı

Kullanıcının girdiği metni okumak ve yönetmek için kullanılır.

TextEditingController controller = TextEditingController();

TextField(
  controller: controller,
),

Metni almak için:

print(controller.text);

📌 Form işlemlerinde olmazsa olmazdır.


7️⃣ Klavye Türünü Değiştirme

TextField(
  keyboardType: TextInputType.emailAddress,
),

🔹 Yaygın klavye türleri:

  • text

  • number

  • phone

  • emailAddress

  • url


8️⃣ Şifre Alanı (Gizli Metin)

TextField(
  obscureText: true,
  decoration: InputDecoration(
    labelText: "Şifre",
  ),
),

📌 obscureText: true → Yazılan karakterleri gizler


9️⃣ Maksimum Karakter Sınırı

TextField(
  maxLength: 20,
),

🔹 Kullanıcıyı sınırlar
🔹 Otomatik sayaç gösterir


🔟 Çok Satırlı TextField

TextField(
  maxLines: 4,
),

📌 Yorum, açıklama, mesaj alanları için idealdir.


1️⃣1️⃣ Anlık Değişimleri Yakalama (onChanged)

TextField(
  onChanged: (value) {
    print(value);
  },
),

📌 Kullanıcı her harf yazdığında tetiklenir
📌 Arama (search) alanlarında çok kullanılır


1️⃣2️⃣ Gönderme Tuşunu Yakalama (onSubmitted)

TextField(
  onSubmitted: (value) {
    print("Girilen değer: $value");
  },
),

🔹 Enter / Done tuşuna basıldığında çalışır


1️⃣3️⃣ TextField Stil Özelleştirme

TextField(
  style: TextStyle(
    fontSize: 18,
    color: Colors.blue,
  ),
),

1️⃣4️⃣ TextAlign ve Metin Hizalama

TextField(
  textAlign: TextAlign.center,
),

1️⃣5️⃣ Enabled / ReadOnly Kullanımı

TextField(
  enabled: false,
),
TextField(
  readOnly: true,
),

🔹 enabled: false → Tamamen pasif
🔹 readOnly: true → Seçilebilir ama yazılamaz


1️⃣6️⃣ TextField vs TextFormField

ÖzellikTextFieldTextFormField
Basit kullanım
Validasyon
Form yapısı

📌 Form kullanıyorsan TextFormField önerilir.


🎯 Ne Zaman TextField Kullanmalıyım?

✔ Arama kutusu
✔ Basit giriş alanları
✔ Anlık veri takibi

❌ Validasyon gerekiyorsa → TextFormField


🧠 Özet

  • TextField, Flutter’da kullanıcı girişi için temel widget’tır

  • Görsel ve işlevsel olarak tamamen özelleştirilebilir

  • controller ile veri kontrol edilir

  • Form işlemleri için TextFormField tercih edilir




1. Temel Kullanım ve Veri Alma

Bir TextField'dan veri almanın iki ana yolu vardır:

  • onChanged: Her karakter değişiminde tetiklenir. Hızlı aramalar için idealdir.

  • TextEditingController: Metni kontrol etmek, temizlemek veya başlangıç değeri atamak için en sağlıklı yöntemdir.

Dart
final TextEditingController _controller = TextEditingController();

TextField(
  controller: _controller,
  onChanged: (text) {
    print("Güncel metin: $text");
  },
)

2. Görsel Özelleştirme: InputDecoration

TextField'ın dış görünüşünü (placeholder, kenarlıklar, ikonlar) decoration parametresi ile yönetiriz.

  • labelText: Kutunun üzerinde duran açıklama.

  • hintText: Kutu boşken görünen ipucu metni.

  • prefixIcon / suffixIcon: Metnin başına veya sonuna ikon ekleme.

  • border: OutlineInputBorder veya UnderlineInputBorder seçenekleri.


3. Klavye ve Girdi Kontrolleri

Kullanıcı deneyimini iyileştirmek için klavye tipini ve metin davranışını sınırlamak çok önemlidir:

ParametreAçıklama
keyboardTypeSayısal (number), E-posta (emailAddress) veya Telefon klavyesi açar.
obscureTextŞifre girişleri için metni gizler (nokta şeklinde gösterir).
textInputActionKlavyedeki "Enter" tuşunun görevini belirler (Ara, Gönder, Sonraki).
maxLengthGirilebilecek maksimum karakter sayısını belirler.

4. Stil ve Biçimlendirme (TextStyle & Formatters)

Metnin rengini, font boyutunu değiştirebilir veya kullanıcının sadece belirli formatlarda yazmasını sağlayabilirsiniz.

  • style: Yazılan metnin rengi, boyutu ve fontu.

  • inputFormatters: Örneğin sadece rakam girilmesini veya bir kredi kartı formatında (0000 0000...) yazılmasını zorunlu kılar.

Dart
TextField(
  style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
  inputFormatters: [FilteringTextInputFormatter.digitsOnly], // Sadece rakam
)

5. Odak Yönetimi (FocusNode)

Bir formda "Sonraki" butonuna basınca diğer kutucuğa geçmek istiyorsanız FocusNode kullanmanız gerekir.

İpucu: autofocus: true yaparak sayfa açılır açılmaz klavyenin otomatik olarak bu kutu için açılmasını sağlayabilirsiniz.


6. TextField vs TextFormField

Eğer bir form yapısı (validasyon/doğrulama gerektiren) kuruyorsanız TextFormField kullanmalısınız.

  • TextFormField, içinde bir validator fonksiyonu barındırır.

  • Boş bırakılamaz veya "geçerli bir e-posta değil" gibi uyarıları otomatik yönetir.


Özet: İdeal Bir TextField Yapılandırması

Dart
TextField(
  controller: _myController,
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(
    labelText: 'E-posta Adresiniz',
    hintText: 'ornek@mail.com',
    prefixIcon: Icon(Icons.email),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(10.0),
    ),
    filled: true,
    fillColor: Colors.grey[200],
  ),
)

🎨 Material 3 Uyumlu Flutter TextField Tasarımı

Modern, Dinamik ve Tema Destekli Giriş Alanları

Material 3, Google tarafından geliştirilen ve dinamik renkler, yumuşak köşeler ve erişilebilirlik odaklı yeni nesil tasarım sistemidir.
Flutter’da Material 3 kullanırken TextField’lar da bu sisteme otomatik olarak uyum sağlayabilir — doğru tema ayarlarıyla.


1️⃣ Material 3 Nedir? (Kısa Hatırlatma)

Material 3 (Material You):

  • 🎨 Dinamik renk sistemi (ColorScheme)

  • 🟦 Daha büyük radius (oval kenarlar)

  • 🧩 Daha sade ve modern input alanları

  • ♿ Daha iyi kontrast & erişilebilirlik

📌 Flutter’da Material 3 varsayılan olarak kapalıdır, açmamız gerekir.


2️⃣ Material 3’ü Projede Aktif Etme (EN KRİTİK ADIM)

MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
  ),
  home: MyHomePage(),
);

✅ Bu satır olmadan Material 3 TextField görünümü gelmez


3️⃣ Material 3 Varsayılan TextField Görünümü

TextField(
  decoration: InputDecoration(
    labelText: "Ad Soyad",
  ),
),

📌 Material 3 ile otomatik olarak:

  • Label animasyonlu

  • Daha yuvarlak kenarlar

  • Daha sade border

  • Modern boşluklar


4️⃣ Material 3’e Uygun Outline Border Tasarımı

TextField(
  decoration: InputDecoration(
    labelText: "E-posta",
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(16),
    ),
  ),
),

🎯 Material 3 önerisi:
borderRadius: 12 – 20 arası


5️⃣ Focused & Enabled Border (Material 3 Stilinde)

TextField(
  decoration: InputDecoration(
    labelText: "Kullanıcı Adı",
    enabledBorder: OutlineInputBorder(
      borderRadius: BorderRadius.circular(16),
      borderSide: BorderSide(
        color: Colors.grey.shade400,
      ),
    ),
    focusedBorder: OutlineInputBorder(
      borderRadius: BorderRadius.circular(16),
      borderSide: BorderSide(
        color: Colors.deepPurple,
        width: 2,
      ),
    ),
  ),
),

📌 Odaklanınca daha belirgin ve yumuşak geçişli görünür


6️⃣ Material 3 + ColorScheme Kullanımı (ÖNERİLEN YOL)

ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.deepPurple,
  ),
);

Ardından TextField:

TextField(
  decoration: InputDecoration(
    labelText: "Telefon",
  ),
),

🎨 Renkler:

  • Primary

  • OnSurface

  • Outline

otomatik olarak ayarlanır ✔


7️⃣ Material 3 İkonlu TextField Tasarımı

TextField(
  decoration: InputDecoration(
    labelText: "E-posta",
    prefixIcon: Icon(Icons.email_outlined),
  ),
),

📌 Material 3’te ikonlar:

  • Daha sade

  • Daha ince

  • Göz yormayan tonlarda


8️⃣ Filled TextField (Material 3 Stil)

TextField(
  decoration: InputDecoration(
    labelText: "Adres",
    filled: true,
    fillColor: Theme.of(context)
        .colorScheme
        .surfaceContainerHighest,
  ),
),

🎯 Material 3’te filled input çok yaygındır
Özellikle:

  • Mobil formlar

  • Tablet / Etkileşimli tahta arayüzleri


9️⃣ Şifre Alanı – Material 3 Uyumlu

TextField(
  obscureText: true,
  decoration: InputDecoration(
    labelText: "Şifre",
    prefixIcon: Icon(Icons.lock_outline),
  ),
),

🔟 Material 3 TextField Tema Seviyesinde Özelleştirme

ThemeData(
  useMaterial3: true,
  inputDecorationTheme: InputDecorationTheme(
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(16),
    ),
    floatingLabelBehavior: FloatingLabelBehavior.auto,
  ),
);

📌 Böylece tüm TextField’lar otomatik bu stilde olur


1️⃣1️⃣ Material 3 – TextField vs Eski Material 2

ÖzellikMaterial 2Material 3
Köşe yapısıKeskinYuvarlak
RenkSabitDinamik
Dolgu (filled)AzYaygın
ErişilebilirlikOrtaYüksek

🎯 Eğitim Ortamları İçin Öneri (ETAP / Tablet)

✔ Büyük radius
✔ Filled TextField
✔ ColorScheme.fromSeed
✔ Yüksek kontrast


🧠 Özet

  • useMaterial3: true şart

  • ColorScheme ile dinamik renkler

  • Büyük radius + sade border

  • Filled TextField Material 3’ün ruhu

  • Tema seviyesinde özelleştirme en doğru yaklaşım


Aşağıda Material 3 (Material You) tasarım diline tam uyumlu, Login / Register (Giriş – Kayıt) ekranını;
✔ tema ayarları
✔ validasyon
✔ modern UI
✔ tek dosyada çalışır örnek

şeklinde eğitim + gerçek proje formatında bulacaksın.


🔐 Material 3 Uyumlu Login / Register Formu (Flutter)

Material 3, Google tarafından geliştirilen modern tasarım sistemidir. Flutter’da doğru tema ile Login / Register ekranları otomatik olarak modern, sade ve erişilebilir hale gelir.


1️⃣ Material 3 Tema Ayarı (ZORUNLU)

MaterialApp(
  debugShowCheckedModeBanner: false,
  theme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.deepPurple,
    ),
    inputDecorationTheme: InputDecorationTheme(
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(16),
      ),
      filled: true,
    ),
  ),
  home: AuthPage(),
);

2️⃣ Login / Register Yapısı (TabBar ile)

📌 Tek sayfa
📌 Üstte Login – Register sekmeleri
📌 Material 3 uyumlu


3️⃣ AuthPage (Ana Ekran)

class AuthPage extends StatelessWidget {
  const AuthPage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: const Text("Hesap İşlemleri"),
          centerTitle: true,
          bottom: const TabBar(
            tabs: [
              Tab(text: "Giriş"),
              Tab(text: "Kayıt Ol"),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            LoginForm(),
            RegisterForm(),
          ],
        ),
      ),
    );
  }
}

4️⃣ Login Formu (Material 3 + Validation)

class LoginForm extends StatefulWidget {
  const LoginForm({super.key});

  @override
  State<LoginForm> createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20),
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            TextFormField(
              decoration: const InputDecoration(
                labelText: "E-posta",
                prefixIcon: Icon(Icons.email_outlined),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return "E-posta boş olamaz";
                }
                return null;
              },
            ),
            const SizedBox(height: 16),
            TextFormField(
              obscureText: true,
              decoration: const InputDecoration(
                labelText: "Şifre",
                prefixIcon: Icon(Icons.lock_outline),
              ),
              validator: (value) {
                if (value == null || value.length < 6) {
                  return "Şifre en az 6 karakter olmalı";
                }
                return null;
              },
            ),
            const SizedBox(height: 24),
            FilledButton(
              onPressed: () {
                if (_formKey.currentState!.validate()) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text("Giriş başarılı")),
                  );
                }
              },
              child: const Text("Giriş Yap"),
            ),
          ],
        ),
      ),
    );
  }
}

5️⃣ Register Formu (Kayıt Ol)

class RegisterForm extends StatefulWidget {
  const RegisterForm({super.key});

  @override
  State<RegisterForm> createState() => _RegisterFormState();
}

class _RegisterFormState extends State<RegisterForm> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20),
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            TextFormField(
              decoration: const InputDecoration(
                labelText: "Ad Soyad",
                prefixIcon: Icon(Icons.person_outline),
              ),
            ),
            const SizedBox(height: 16),
            TextFormField(
              decoration: const InputDecoration(
                labelText: "E-posta",
                prefixIcon: Icon(Icons.email_outlined),
              ),
            ),
            const SizedBox(height: 16),
            TextFormField(
              obscureText: true,
              decoration: const InputDecoration(
                labelText: "Şifre",
                prefixIcon: Icon(Icons.lock_outline),
              ),
            ),
            const SizedBox(height: 24),
            FilledButton(
              onPressed: () {
                if (_formKey.currentState!.validate()) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text("Kayıt başarılı")),
                  );
                }
              },
              child: const Text("Kayıt Ol"),
            ),
          ],
        ),
      ),
    );
  }
}

6️⃣ Material 3 Tasarım Özellikleri (Bu Örnekte)

useMaterial3: true
ColorScheme.fromSeed
✅ Filled TextField
✅ Büyük radius (16)
FilledButton (Material 3 buton)
✅ Modern ikonlar


7️⃣ Eğitim & Proje İçin İdeal Kullanım

✔ 11. sınıf Mobil Uygulamalar
✔ Firebase Auth entegrasyonuna hazır
✔ Tablet / ETAP uyumlu
✔ Gerçek uygulamaya dönüştürülebilir


 Bir Form yapısı kurarak verileri nasıl kontrol edeceğimizi (Validation) ve kullanıcı hatalarını nasıl engelleyeceğimizi inceleyelim.


1. TextFormField ve Form Kontrolü

Sıradan bir TextField yerine TextFormField kullanmanın en büyük avantajı, tüm girişleri tek bir yerden (GlobalKey ile) kontrol edebilmektir.

Form ve GlobalKey Kurulumu

Öncelikle formun durumunu takip edecek bir anahtar tanımlamalıyız:

Dart
final _formKey = GlobalKey<FormState>(); // Formun "kimliği"
String _userEmail = '';

Validator (Doğrulama) Kullanımı

validator fonksiyonu, kullanıcı "Gönder" butonuna bastığında çalışır. Eğer metin uygun değilse bir hata mesajı döner, uygunsa null döner.

Dart
Form(
  key: _formKey, // Formu anahtara bağlıyoruz
  child: Column(
    children: [
      TextFormField(
        decoration: InputDecoration(
          labelText: 'E-posta',
          border: OutlineInputBorder(),
        ),
        // Doğrulama Mantığı:
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Lütfen e-posta adresinizi girin';
          }
          if (!value.contains('@')) {
            return 'Geçerli bir e-posta adresi giriniz';
          }
          return null;
        },
        onSaved: (value) => _userEmail = value!,
      ),
      
      ElevatedButton(
        onPressed: () {
          // Formu kontrol et:
          if (_formKey.currentState!.validate()) {
            // Eğer her şey yolundaysa veriyi kaydet
            _formKey.currentState!.save();
            print("Kaydedilen veri: $_userEmail");
          }
        },
        child: Text('Giriş Yap'),
      ),
    ],
  ),
)

2. InputFormatters: Veriyi Yazılırken Sınırlamak

Kullanıcının yanlış veri girmesini en baştan engellemek, hata mesajı göstermekten daha iyidir. inputFormatters tam da burada devreye girer.

  • Sadece Rakam İzni: FilteringTextInputFormatter.digitsOnly

  • Karakter Sınırı: LengthLimitingTextInputFormatter(10)

  • Özel Maskeleme: (Örn: Telefon numarası formatı (5xx) xxx xx xx)

Dart
TextFormField(
  keyboardType: TextInputType.phone,
  inputFormatters: [
    FilteringTextInputFormatter.digitsOnly, // Harf girişini engeller
    LengthLimitingTextInputFormatter(11),   // 11 haneden fazlasını engeller
  ],
  decoration: InputDecoration(hintText: "Telefon Numaranız"),
)

3. FocusNode ile Odak Yönetimi

Özellikle okul projelerinde veya karmaşık formlarda, kullanıcı e-postayı bitirip "İleri" (Next) dediğinde otomatik olarak şifre kutusuna geçmesi istenir.

Dart
FocusNode _passwordFocus = FocusNode();

// İlk kutu (E-posta)
TextFormField(
  textInputAction: TextInputAction.next, // Klavyede "İleri" butonu gösterir
  onFieldSubmitted: (v) {
    FocusScope.of(context).requestFocus(_passwordFocus); // Şifre kutusuna odaklan
  },
),

// İkinci kutu (Şifre)
TextFormField(
  focusNode: _passwordFocus,
  obscureText: true,
  decoration: InputDecoration(labelText: "Şifre"),
),

Özet Tablo: TextField Güvenliği ve UX

ÖzellikKullanım AmacıÖnem Derecesi
validatorVerinin doğruluğunu (email mi, boş mu?) kontrol eder.Kritik
obscureTextŞifrelerin görünmesini engeller.Kritik
autocorrectYanlış yazım düzeltmeyi açar/kapatır (Şifrelerde kapatılmalıdır).Orta
enableSuggestionsKlavye üzerinde kelime önerileri sunar.Düşük

Bu yapı, özellikle Pardus ETAP gibi etkileşimli tahta uygulamalarında kullanıcıdan hızlı ve hatasız veri almak için standarttır.

Harika! O zaman şimdiye kadar öğrendiğimiz TextFormField, Form, Validation ve Controller yapılarını bir araya getiren somut bir uygulama yapalım.

Bu örnekte, bir "Öğrenci Kayıt Paneli" hazırlayacağız. Kullanıcı ismi girecek, biz bunu doğrulayacağız ve butona basıldığında listeye anlık olarak ekleyeceğiz.


Öğrenci Kayıt Uygulaması Taslağı

Bu uygulama, hem form yönetimini hem de Flutter'daki State (Durum) yönetimini anlamanı sağlayacak.

Dart
import 'package:flutter/material.dart';

class OgrenciKayitSayfasi extends StatefulWidget {
  @override
  _OgrenciKayitSayfasiState createState() => _OgrenciKayitSayfasiState();
}

class _OgrenciKayitSayfasiState extends State<OgrenciKayitSayfasi> {
  final _formKey = GlobalKey<FormState>(); // Formun kontrol anahtarı
  final TextEditingController _adController = TextEditingController(); // Metni almak için
  List<String> ogrenciListesi = []; // Eklenen isimlerin tutulduğu liste

  void _ogrenciEkle() {
    // 1. Form doğrulaması yapılıyor mu?
    if (_formKey.currentState!.validate()) {
      setState(() {
        // 2. Listeye yeni ismi ekle
        ogrenciListesi.add(_adController.text);
        // 3. Yazı alanını temizle
        _adController.clear();
      });
      // Klavyeyi kapat
      FocusScope.of(context).unfocus();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Pardus ETAP Öğrenci Kayıt")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // --- FORM ALANI ---
            Form(
              key: _formKey,
              child: Row(
                children: [
                  Expanded(
                    child: TextFormField(
                      controller: _adController,
                      decoration: InputDecoration(
                        labelText: 'Öğrenci Adı Soyadı',
                        border: OutlineInputBorder(),
                        prefixIcon: Icon(Icons.person),
                      ),
                      // Doğrulama: Boş bırakılırsa hata ver
                      validator: (value) {
                        if (value == null || value.isEmpty) {
                          return 'İsim boş olamaz!';
                        }
                        return null;
                      },
                    ),
                  ),
                  SizedBox(width: 10),
                  ElevatedButton(
                    onPressed: _ogrenciEkle,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 15),
                      child: Text("EKLE"),
                    ),
                  ),
                ],
              ),
            ),
            Divider(height: 40, thickness: 2),
            // --- LİSTELEME ALANI ---
            Expanded(
              child: ogrenciListesi.isEmpty
                  ? Center(child: Text("Henüz öğrenci eklenmedi."))
                  : ListView.builder(
                      itemCount: ogrenciListesi.length,
                      itemBuilder: (context, index) {
                        return Card(
                          child: ListTile(
                            leading: CircleAvatar(child: Text("${index + 1}")),
                            title: Text(ogrenciListesi[index]),
                            trailing: IconButton(
                              icon: Icon(Icons.delete, color: Colors.red),
                              onPressed: () {
                                setState(() {
                                  ogrenciListesi.removeAt(index);
                                });
                              },
                            ),
                          ),
                        );
                      },
                    ),
            ),
          ],
        ),
      ),
    );
  }
}

Neler Öğrendik? (Kritik Noktalar)

  • Expanded Kullanımı: ListView ve TextFormField gibi widget'lar Column içinde çakışmaması için Expanded ile sarıldı. Bu, özellikle akıllı tahtalarda ekranın verimli kullanılması için önemlidir.

  • setState Gücü: Listeye bir eleman eklediğimizde ekranın anlık olarak güncellenmesi için setState kullandık.

  • ListView.builder: Liste uzadıkça performans kaybı yaşanmaması için elemanları sadece ekrana geldikçe oluşturan bu yapıyı tercih ettik.

  • Hızlı Temizlik: _adController.clear() ile kullanıcı her ekleme yaptığında kutucuğu bir sonraki giriş için hazırladık.


Bir Sonraki Adım: Veritabanı?

Bu veriler şu an sadece uygulama açıkken RAM'de tutuluyor. Uygulamayı kapatıp açtığında liste sıfırlanacaktır.

Görsel yapı ve temalandırma (UI/UX), bir uygulamanın sadece "çalışan" bir araçtan "keyifle kullanılan" bir deneyime dönüşmesini sağlar. Özellikle Pardus ETAP gibi geniş ekranlı veya akıllı tahta ortamlarında, kontrastı yüksek ve göz yormayan tasarımlar çok önemlidir.

Şimdi TextField ve uygulama genelini ThemeData kullanarak nasıl modernize edebileceğimize bakalım.


1. Merkezi Tema Yönetimi (ThemeData)

Her TextField için tek tek renk tanımlamak yerine, uygulamanın ana temasında (MaterialApp) bir standart belirlemek en profesyonel yaklaşımdır.

Dart
MaterialApp(
  theme: ThemeData(
    primaryColor: Colors.blueGrey[900],
    inputDecorationTheme: InputDecorationTheme(
      filled: true,
      fillColor: Colors.blueGrey[50],
      labelStyle: TextStyle(color: Colors.blueGrey[700]),
      focusedBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.blueAccent, width: 2),
        borderRadius: BorderRadius.circular(15),
      ),
      enabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.grey),
        borderRadius: BorderRadius.circular(15),
      ),
      errorBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.red, width: 2),
        borderRadius: BorderRadius.circular(15),
      ),
    ),
  ),
  home: OgrenciKayitSayfasi(),
);

2. TextField İçin Görsel İpuçları ve Efektler

Kullanıcı etkileşimini artırmak için şu üç özelliği kullanabiliriz:

A. Floating Label Style (Yüzen Etiket)

Metin kutusuna tıklandığında yukarı kayan etiketin rengini ve stilini floatingLabelStyle ile değiştirebilirsiniz.

B. Gradient Arka Plan (Konteyner ile)

TextField'ı bir Container içine alarak ona degrade (geçişli) renkler verebiliriz.

C. İnteraktif İkonlar

suffixIcon kullanarak şifreyi göster/gizle veya metni temizle butonları eklemek kullanıcı dostudur.


3. Gelişmiş Tasarımlı "Öğrenci Kartı"

Listede görünen her bir öğrenciyi sıradan bir metin yerine, daha şık bir Card yapısına kavuşturalım:

Dart
Widget _ogrenciKart(String isim, int index) {
  return Container(
    margin: EdgeInsets.symmetric(vertical: 5),
    decoration: BoxDecoration(
      gradient: LinearGradient(
        colors: [Colors.blueAccent.withOpacity(0.1), Colors.white],
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      ),
      borderRadius: BorderRadius.circular(12),
      border: Border.all(color: Colors.blueAccent.withOpacity(0.3)),
    ),
    child: ListTile(
      leading: CircleAvatar(
        backgroundColor: Colors.blueAccent,
        child: Text("${index + 1}", style: TextStyle(color: Colors.white)),
      ),
      title: Text(
        isim,
        style: TextStyle(fontWeight: FontWeight.bold, letterSpacing: 1.1),
      ),
      trailing: Icon(Icons.chevron_right, color: Colors.blueAccent),
    ),
  );
}

4. Dark Mode (Karanlık Mod) Desteği

Akıllı tahtalarda akşam saatlerinde veya loş ışıkta göz yorgunluğunu önlemek için karanlık mod şarttır. Flutter'da bunu tek satırla ekleyebilirsiniz:

Dart
darkTheme: ThemeData.dark().copyWith(
  inputDecorationTheme: InputDecorationTheme(
    fillColor: Colors.grey[800],
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Colors.amber),
    ),
  ),
),
themeMode: ThemeMode.system, // Sistemin ayarına göre otomatik değişir

Tasarım İpucu: Pardus Kurumsal Renkleri

Uygulamanı Pardus ekosistemine daha uygun hale getirmek istersen:

  • Ana Renk: #1d2b3a (Koyu Lacivert)

  • Vurgu Rengi: #f39200 (Pardus Turuncusu)

Bu renkleri Color(0xFF1D2B3A) şeklinde kullanarak kurumsal bir görünüm elde edebilirsin.

Yorumlar

Bu blogdaki popüler yayınlar

Dart Uygulama Sınavı: Pardus ETAP 23 Kurulum Otomasyonu

Dart Programlama Dil Uygulama Sınavı Çalışma Soruları

Pardus Üzerinde Flutter Geliştirme Ortamı Kurulumu