Flutter İle Liste Görünümünde Arama Filtreleme İşlemi Nasıl Yapılır?

Flutter İle Liste Görünümünde Arama Filtreleme İşlemi Nasıl Yapılır?
Flutter İle Liste Görünümünde Arama Filtreleme İşlemi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu projeyi başarıyla tamamlamak için bilgisayarınızda Flutter SDK'nın 3.20 veya daha yeni bir sürümünün kurulu olması gerekmektedir. Projenizi oluştururken Dart dilinin güncel null-safety (boş değer güvenliği) standartlarını kullandığınızdan emin olun.

  • Flutter SDK 3.20+
  • Dart 3.0+
  • VS Code veya Android Studio gibi bir IDE
  • Temel düzeyde StatefulWidget bilgisi

Projenizi başlatmak için terminalinizde flutter create arama_uygulamasi komutunu çalıştırarak yeni bir proje oluşturabilirsiniz.

Veri Modelini ve Temel Listeyi Oluşturma

Filtreleme işlemine başlamadan önce, üzerinde işlem yapacağımız veri yapısını tanımlamalıyız. Basit bir "Kullanıcı" modeli üzerinden ilerleyeceğiz. Bu model, arama yapacağımız isim ve departman gibi alanları içerecektir.

class Kullanici {
  final String isim;
  final String departman;

  Kullanici({required this.isim, required this.departman});
}

final List tumKullanicilar = [
  Kullanici(isim: "Ahmet Yılmaz", departman: "Yazılım"),
  Kullanici(isim: "Ayşe Demir", departman: "Tasarım"),
  Kullanici(isim: "Mehmet Kaya", departman: "Pazarlama"),
];

Burada Kullanici sınıfını tanımladık ve tumKullanicilar adında statik bir liste oluşturduk. Bu liste, filtreleme işlemi sırasında ana veri kaynağımız olarak kalacak ve asla doğrudan değiştirilmeyecektir.

Arama Filtreleme Mantığını Kurma

Filtreleme işleminin temel mantığı, ana listeyi koruyup, arama terimine göre bu listeden süzülen yeni bir liste oluşturmaktır. Kullanıcı bir harf girdiğinde, setState metodu ile arayüzü güncelleyerek filtreleme fonksiyonunu tetiklememiz gerekir.

List gorunenListe = [];

void filtrele(String arananKelime) {
  List sonuclar = [];
  if (arananKelime.isEmpty) {
    sonuclar = tumKullanicilar;
  } else {
    sonuclar = tumKullanicilar.where((kullanici) =>
        kullanici.isim.toLowerCase().contains(arananKelime.toLowerCase())).toList();
  }
  setState(() {
    gorunenListe = sonuclar;
  });
}

filtrele fonksiyonu, where operatörünü kullanarak ana listede arama yapar. toLowerCase() kullanımı, aramanın büyük/küçük harf duyarsız (case-insensitive) olmasını sağlar.

TextField ile Kullanıcı Girdisini Yakalama

Kullanıcıdan arama metnini almak için TextField widget'ını kullanırız. onChanged parametresi, her karakter girişinde filtreleme fonksiyonumuzu tetikleyecektir.

TextField(
  onChanged: (deger) => filtrele(deger),
  decoration: InputDecoration(
    labelText: 'Arama',
    prefixIcon: Icon(Icons.search),
    border: OutlineInputBorder(),
  ),
)

Bu widget, kullanıcı her tuşa bastığında filtrele fonksiyonuna güncel metni gönderir. prefixIcon kullanımı, arama çubuğunun daha profesyonel görünmesini sağlar.

ListView.builder Kullanarak Sonuçları Gösterme

Filtrelenmiş veriyi ekranda göstermek için ListView.builder en performanslı yöntemdir. Bu widget, sadece ekranda görünen öğeleri oluşturarak bellek kullanımını minimize eder.

Expanded(
  child: ListView.builder(
    itemCount: gorunenListe.length,
    itemBuilder: (context, index) {
      return ListTile(
        title: Text(gorunenListe[index].isim),
        subtitle: Text(gorunenListe[index].departman),
      );
    },
  ),
)

itemCount kısmına mutlaka gorunenListe.length değerini vermelisiniz. Aksi takdirde, filtreleme yapıldığında liste indeksi dışına çıkma hatalarıyla (RangeError) karşılaşabilirsiniz.

Filtreleme Yöntemlerinin Karşılaştırılması

Aşağıdaki tabloda, Flutter'da arama filtreleme yaparken kullanılan farklı yaklaşımların avantaj ve dezavantajlarını görebilirsiniz.

Yöntem Avantajı Dezavantajı
StatefulWidget (Local) Hızlı ve basit kurulum Büyük verilerde performans düşebilir
Debounce (Bekletme) Gereksiz işlem yükünü azaltır Ekstra kütüphane gerektirebilir
API Tabanlı Arama Sunucu taraflı yüksek performans İnternet bağlantısı zorunludur

Güvenlik Uyarısı: Eğer arama verilerini bir API'ye gönderiyorsanız, mutlaka "Debounce" tekniğini kullanın. Bu, kullanıcının her tuş vuruşunda sunucuya istek atılmasını engelleyerek hem sunucu yükünü azaltır hem de API anahtarınızın kötüye kullanımını zorlaştırır.

Sıkça Sorulan Sorular

Arama yaparken büyük/küçük harf duyarlılığını nasıl kaldırırım?

Hem aranan metni hem de listedeki veriyi .toLowerCase() veya .toUpperCase() metodları ile aynı formata getirerek karşılaştırma yapmalısınız.

Liste boş olduğunda "Sonuç bulunamadı" mesajını nasıl gösteririm?

gorunenListe.isEmpty kontrolü yaparak, eğer liste boşsa bir Center(child: Text("Sonuç bulunamadı")) widget'ı döndürebilirsiniz.

Arama çok yavaş çalışıyor, ne yapmalıyım?

Eğer liste binlerce öğeden oluşuyorsa, setState yerine ValueListenableBuilder veya Bloc/Provider gibi daha gelişmiş state yönetimi çözümlerini tercih etmelisiniz.

Debounce (Gecikmeli Arama) nedir?

Kullanıcı yazmayı bıraktıktan sonra (örneğin 500ms sonra) arama işlemini tetikleyen bir tekniktir. Bu, işlemciyi yormamak için kritiktir.

Arama çubuğunu nasıl temizlerim?

TextEditingController kullanarak controller.clear() metodunu çağırabilir ve ardından filtreleme fonksiyonunuzu boş bir string ile tekrar tetikleyebilirsiniz.

Gelişmiş Filtreleme: Çoklu Kriter ile Arama

Basit bir metin eşleşmesinin ötesine geçmek istediğinizde, kullanıcıların aynı anda birden fazla kriterle (örneğin hem isim hem de kategori) arama yapmasını sağlamak uygulamanızın kullanıcı deneyimini (UX) ciddi oranda artırır. Bu senaryoda, verileriniz üzerinde where sorgusunu genişleterek daha kapsamlı bir filtreleme mantığı kurabilirsiniz.

Aşağıdaki örnekte, hem ürün adını hem de ürünün bulunduğu kategoriyi aynı anda kontrol eden bir filtreleme mekanizması yer almaktadır:

void _runFilter(String enteredKeyword) {
  List results = [];
  if (enteredKeyword.isEmpty) {
    results = allProducts;
  } else {
    results = allProducts.where((product) =>
      product["name"].toLowerCase().contains(enteredKeyword.toLowerCase()) ||
      product["category"].toLowerCase().contains(enteredKeyword.toLowerCase())
    ).toList();
  }

  setState(() {
    _foundProducts = results;
  });
}

Filtreleme İşlemlerinde Performans Optimizasyonu

Büyük veri setleri ile çalışırken, her tuş vuruşunda (onChanged) tüm listeyi filtrelemek ana iş parçacığını (main thread) yorabilir ve arayüzde donmalara neden olabilir. Bu durumu engellemek için Isolate kullanımı veya Debounce teknikleri hayati önem taşır.

Isolate ile Ağır İşlemleri Arka Plana Taşıma

Eğer binlerce öğeden oluşan bir listeniz varsa, filtreleme işlemini compute fonksiyonu ile ayrı bir izole (isolate) üzerinde çalıştırmak, uygulamanızın 60 FPS akıcılığını korumasını sağlar.

import 'package:flutter/foundation.dart';

// Filtreleme işlemini ana thread'den ayırıyoruz
Future filterData(List data, String query) async {
  return compute(_performFiltering, {'data': data, 'query': query});
}

List _performFiltering(Map params) {
  final data = params['data'] as List;
  final query = params['query'] as String;
  
  return data.where((item) => 
    item.title.toLowerCase().contains(query.toLowerCase())
  ).toList();
}

Bellek Yönetimi İpuçları

  • ListView.builder Kullanımı: Asla ListView içerisine tüm verileri manuel olarak çocuk (children) olarak eklemeyin. builder metodu, sadece ekranda görünen öğeleri oluşturarak bellek kullanımını minimize eder.
  • Gereksiz Yeniden Oluşturmalar: Filtreleme sonucunda elde edilen listeyi State içerisinde tutarken, listenin referansını değiştirmek yerine List.from() kullanarak yeni bir kopya oluşturun.
  • Görsel Önbellekleme: Eğer arama sonuçlarında resimler gösteriyorsanız, cached_network_image gibi paketler kullanarak ağ trafiğini ve bellek tüketimini optimize edin.

Bu optimizasyon teknikleri, özellikle düşük donanımlı cihazlarda uygulamanızın performansını doğrudan etkileyecek ve kullanıcıların arama yaparken takılma hissetmemesini sağlayacaktır.

Sonuç

Flutter ile liste görünümünde arama filtreleme işlemi, doğru state yönetimi ve verimli widget kullanımı ile oldukça basit bir süreçtir. Bu rehberde, statik bir listeden başlayarak dinamik bir arama arayüzü oluşturmayı öğrendik. Bir sonraki adım olarak, bu verileri yerel bir veritabanından (SQLite) veya uzak bir API'den çekerek filtreleme mantığını daha karmaşık senaryolara uyarlayabilirsiniz.

Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamındaki uygulamalarınızda kullanıcı verilerini işlerken, veri gizliliğine ve güvenliğine (GDPR/KVKK) uygun yöntemler kullanmanız, girdi sanitasyonu yapmanız ve dış servislerle iletişimde güvenli protokoller (HTTPS) tercih etmeniz gerekmektedir.

Bu yazıya tepkinizi paylaşın:
Deniz Aydın

On yıldır dijital yayıncılıkta pratik çözüm rehberleri hazırlıyorum. Karmaşık süreçleri herkesin anlayabileceği adım adım yönergelere dönüştürme konusunda uzmanım.

Yorumlar (0)

Yorum Yaz