Gereksinimler ve Ön Hazırlık
Bu eğitimde yer alan kod örneklerini çalıştırabilmek için bilgisayarınızda Flutter SDK'nın 3.24 veya daha güncel bir sürümünün yüklü olması gerekmektedir. Projenizi oluştururken terminal üzerinden flutter create arama_uygulamasi komutunu kullanarak temiz bir başlangıç yapabilirsiniz.
- Flutter SDK (3.24+)
- Dart 3.5+
- VS Code veya Android Studio (Flutter eklentileri kurulu olmalı)
- Temel düzeyde Stateful Widget bilgisi
Arama işlemini gerçekleştirirken performans kaybı yaşamamak adına, listenin çok büyük olduğu durumlarda "Debounce" (gecikmeli işlem) mekanizmasının önemini unutmamalısınız. Şimdi, temel bir veri yapısı oluşturarak işe başlayalım.
Adım Adım Liste ve Filtreleme Mantığını Kurma
İlk adımda, üzerinde arama yapacağımız bir liste tanımlamamız gerekiyor. Bu liste, genellikle bir API'den gelen verileri temsil eder. Filtreleme işlemi için orijinal listeyi saklayan bir değişken ve ekranda gösterilecek olan filtrelenmiş listeyi tutan bir değişken kullanacağız.
// Veri modelimiz ve liste tanımlaması
List tumKullanicilar = ["Ahmet", "Ayşe", "Mehmet", "Zeynep", "Can", "Deniz"];
List filtrelenmisListe = [];
@override
void initState() {
super.initState();
filtrelenmisListe = tumKullanicilar;
}
Yukarıdaki kod bloğunda, tumKullanicilar değişkeni ana veri kaynağımızı, filtrelenmisListe ise arama sonucunda kullanıcıya gösterilecek veriyi temsil eder. initState içerisinde başlangıçta tüm verilerin gösterilmesini sağlıyoruz.
Arama Fonksiyonunu Yazma
Kullanıcı arama çubuğuna bir metin girdiğinde, bu metni mevcut listemizdeki elemanlarla karşılaştırmamız gerekir. Bu işlem için setState metodu içerisinde çalışan bir filtreleme mantığı kullanacağız.
void aramaYap(String sorgu) {
List sonuclar = [];
if (sorgu.isEmpty) {
sonuclar = tumKullanicilar;
} else {
sonuclar = tumKullanicilar
.where((kullanici) => kullanici.toLowerCase().contains(sorgu.toLowerCase()))
.toList();
}
setState(() {
filtrelenmisListe = sonuclar;
});
}
Bu fonksiyon, büyük/küçük harf duyarlılığını ortadan kaldırmak için toLowerCase() metodunu kullanır. where metodu, listenin her bir elemanını sorgu ile karşılaştırır ve eşleşenleri yeni bir listeye ekler.
Arayüzde TextField ile Entegrasyon
Filtreleme mantığını arayüze bağlamak için TextField widget'ının onChanged parametresini kullanırız. Bu parametre, kullanıcı her tuşa bastığında tetiklenir.
TextField(
onChanged: (deger) => aramaYap(deger),
decoration: InputDecoration(
labelText: 'Ara',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
),
)
Bu yapı, kullanıcı her karakter girdiğinde aramaYap fonksiyonunu çağırır ve listenin anlık olarak güncellenmesini sağlar. prefixIcon kullanımı, kullanıcıya arama çubuğu olduğunu görsel olarak bildirmek için standart bir yaklaşımdır.
Performans İyileştirmesi: Debounce Kullanımı
Kullanıcı çok hızlı yazıyorsa, her harfte filtreleme yapmak (özellikle veri seti binlerce satırsa) performans sorunlarına yol açabilir. Bunun önüne geçmek için Timer kullanarak arama işlemini belirli bir milisaniye geciktirebiliriz.
Timer? _debounce;
void aramaYapDebounced(String sorgu) {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
aramaYap(sorgu);
});
}
Bu yöntem, kullanıcı yazmayı bıraktıktan 500 milisaniye sonra filtreleme işlemini başlatır. Bu, uygulamanızın daha akıcı kalmasını sağlar ve gereksiz işlem yükünü engeller.
Filtreleme Yöntemlerinin Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Anlık Filtreleme (onChanged) | Çok hızlı geri bildirim | Büyük listelerde donma yapabilir |
| Debounce Filtreleme | Yüksek performans | Kullanıcı için hafif bir gecikme hissi |
| Butonlu Filtreleme | Düşük işlemci tüketimi | Kötü kullanıcı deneyimi |
Güvenlik Uyarısı: Kullanıcıdan alınan arama verilerini doğrudan bir veritabanı sorgusuna (SQL) dahil ediyorsanız, mutlaka "Parameterized Query" (parametreleştirilmiş sorgu) kullanın. Kullanıcı girdisini asla doğrudan SQL metnine eklemeyin; bu, SQL Injection saldırılarına kapı aralar.
Sıkça Sorulan Sorular
Arama sonucunda hiç veri bulunamazsa ne yapmalıyım?
Listenin boş olup olmadığını filtrelenmisListe.isEmpty kontrolü ile denetleyerek, kullanıcıya "Sonuç bulunamadı" şeklinde bir Text veya Lottie animasyonu göstermeniz en iyi pratiktir.
Büyük veri setlerinde liste nasıl yönetilir?
Binlerce satırlık verilerde ListView.builder kullanmalı ve filtreleme işlemini arka planda (Isolate) veya bir state management kütüphanesi (Bloc, Riverpod) ile yönetmelisiniz.
Arama çubuğunu nasıl temizleyebilirim?
TextEditingController kullanarak controller.clear() metodunu çağırabilir ve ardından aramaYap("") fonksiyonunu tetikleyerek listeyi eski haline döndürebilirsiniz.
Filtreleme işlemi neden yavaş çalışıyor?
Filtreleme mantığınızın içerisinde karmaşık nesne dönüşümleri yapıyorsanız, bu işlemler build metodunu tetiklediği için yavaşlık hissedilebilir. İşlemleri compute fonksiyonu ile ana thread dışına taşıyabilirsiniz.
Arama çubuğuna özel klavye türü eklenebilir mi?
Evet, TextField içerisindeki keyboardType parametresini TextInputType.text veya ihtiyaca göre TextInputType.name olarak ayarlayabilirsiniz.
İleri Seviye Filtreleme: Çoklu Kriterli Arama Stratejileri
Basit bir metin tabanlı filtreleme genellikle kullanıcı deneyimi için yeterli olsa da, profesyonel uygulamalarda birden fazla parametreye göre (kategori, tarih, fiyat aralığı vb.) filtreleme yapmanız gerekebilir. Bu durumda, tek bir String yerine bir FilterModel nesnesi kullanarak filtreleme mantığınızı genişletebilirsiniz.
Çoklu Parametre ile Filtreleme Mantığı
Kullanıcının hem isim hem de kategori seçimi yapabildiği bir senaryoda, filtreleme fonksiyonunuzu şu şekilde güncelleyebilirsiniz:
List filterProducts(String query, String category) {
return allProducts.where((product) {
final nameMatches = product.name.toLowerCase().contains(query.toLowerCase());
final categoryMatches = category == 'Hepsi' || product.category == category;
return nameMatches && categoryMatches;
}).toList();
}
Bu yaklaşım, kullanıcı arayüzünde DropdownButton veya Chip bileşenleri ile birleştirildiğinde oldukça esnek bir arama deneyimi sunar. Filtreleme kriterleriniz arttıkça, bu mantığı bir ChangeNotifier veya Bloc içerisine taşıyarak state yönetimini daha temiz hale getirebilirsiniz.
Filtreleme İşlemlerinde Hata Ayıklama ve Test Süreçleri
Filtreleme mekanizmalarında en sık karşılaşılan hatalar; boş liste durumlarının (null safety) yönetilememesi, büyük/küçük harf duyarlılığı sorunları ve asenkron veri çekme işlemlerinde arama tetiklenmesidir. Uygulamanızın kararlı çalışması için şu test stratejilerini izlemelisiniz:
- Birim Testleri (Unit Tests): Filtreleme fonksiyonunuzu UI'dan bağımsız olarak test edin. Farklı girdi kombinasyonları için beklenen çıktıları doğrulayın.
- Boş Durum Kontrolü: Liste boşaldığında kullanıcıya "Sonuç bulunamadı" gibi bir geri bildirim göstermek için
isEmptykontrolünü mutlaka kullanın. - Hız Testi: Çok büyük veri setlerinde (10.000+ öğe) filtreleme işleminin ana iş parçacığını (main thread) dondurup dondurmadığını gözlemleyin. Eğer donma oluyorsa
computefonksiyonu ile filtrelemeyi arka planda çalıştırın.
Arka Planda Filtreleme (Isolate Kullanımı)
Eğer veri setiniz çok büyükse, filtreleme işlemini compute fonksiyonu ile ayrı bir izole (isolate) üzerinde gerçekleştirmek, arayüzün akıcılığını korumanızı sağlar:
import 'package:flutter/foundation.dart';
// Filtreleme işlemini ayrı bir izolede çalıştır
Future performHeavyFiltering(List list, String query) async {
return await compute(_filterTask, {'list': list, 'query': query});
}
List _filterTask(Map data) {
final list = data['list'] as List;
final query = data['query'] as String;
return list.where((p) => p.name.contains(query)).toList();
}
Bu yöntem, özellikle karmaşık nesne hiyerarşilerine sahip listelerde uygulamanın "donma" (jank) sorunlarını tamamen ortadan kaldıracaktır. compute kullanımı, CPU yoğunluklu işlemleri ana iş parçacığından ayırarak 60 FPS performansını korumanıza yardımcı olur.
Sonuç
Flutter ile liste arama filtreleme işlemi, doğru teknikler kullanıldığında uygulamanızın kalitesini ve kullanılabilirliğini doğrudan artıran bir özelliktir. Bu rehberde, temel filtreleme mantığından başlayarak performans odaklı Debounce kullanımına kadar gerekli tüm adımları inceledik. Bir sonraki adım olarak, bu filtreleme mantığını bir SearchDelegate sınıfı ile daha modüler hale getirmeyi veya API'den gelen verilerle entegre etmeyi deneyebilirsiniz.
Yasal Sorumluluk Reddi: Bu makalede sağlanan kodlar eğitim amaçlıdır. Üretim ortamındaki uygulamalarınızda veri güvenliği ve performans optimizasyonlarını kendi projenizin gereksinimlerine göre profesyonelce yapılandırmalısınız.


Yorumlar (0)
Yorum Yaz