Pull-to-Refresh: temeller, RefreshControl ve UIRefreshControl

Yazar: IT Sectr Yayınlanma: 2026-02-27 Okuma süresi: 8 dk
Pull-to-Refresh, kullanıcının parmağıyla listeyi aşağı çekerek yeni verilerin yüklenmesini başlattığı bir mobil arayüz desenidir. Harekete görsel bir gösterge — dönen bir spinner veya animasyonlu simge — eşlik eder ve yükleme tamamlandığında kaybolur. Apple HIG UX analizine göre, Pull-to-Refresh Tweetie'de (2008) tanıtılması ve ardından Apple ve Google tarafından standartlaştırılmasından bu yana haber akışlarında, sosyal ağlarda ve e-posta istemcilerinde standart içerik güncelleme mekanizması haline gelmiştir.

Önemli Noktalar

  • Pull-to-Refresh, görsel bir yükleme göstergesi eşliğinde verileri yenilemek için listeyi aşağı çekme hareketidir.
  • iOS'ta UIRefreshControl (iOS 6+) kullanılır, refreshControl özelliği aracılığıyla UITableViewController veya UIScrollView'e eklenir.
  • Android'de SwipeRefreshLayout (Support Library'den) kullanılır — RecyclerView veya NestedScrollView için bir ViewGroup sarmalayıcısı.
  • Her iki API de dinleyiciler aracılığıyla renk, gösterge ve geri arama özelleştirmesini destekler (iOS: UIRefreshControl.target-action, Android: setOnRefreshListener).
  • Liste üst konumda olmadığında Pull-to-Refresh otomatik olarak engellenir — kaydırma ile çakışma mimari olarak hariç tutulmuştur.

Pull-to-Refresh Nedir?

Pull-to-Refresh, kullanıcının içeriği yenilemek için bir listeyi veya kaydırılabilir alanı aşağı çektiği (pull down) bir kullanıcı arayüzü desenidir. Görsel olarak, harekete ekranın üst kısmında beliren ve veri alındıktan sonra kaybolan bir yükleme göstergesi (spinner) eşlik eder. Desen, iPhone için Tweetie uygulaması (2008) tarafından popüler hale getirilmiş ve daha sonra Apple (iOS 6 — UIRefreshControl) ve Google (Android Support Library — SwipeRefreshLayout) tarafından standartlaştırılmıştır.

Teknik açıdan Pull-to-Refresh, kaydırma (parmak yer değiştirmesini izleme) ve bir eşiğe ulaşıldığında tetiklemenin bir kombinasyonudur. Kullanıcı, direncin (dirençli aşırı kaydırma) üstesinden gelerek listeyi aşağı çeker ve eşiği (~80px iOS'ta, ~64dp Android'te) aştıktan sonra gösterge animasyonu ve asenkron yükleme başlar. Kullanıcı parmağını eşikten önce bırakırsa, liste yenilenmeden orijinal konumuna geri döner.

Material Design Kurallarına göre, Pull-to-Refresh gezinme veya sekme değiştirme için kullanılmamalıdır — tek amacı veri yenilemedir. IT Sectr'de, veri tazeliğinin kullanıcı deneyimi için kritik olduğu haber akışlarında, sipariş listelerinde ve sohbetlerde Pull-to-Refresh kullanıyoruz.

iOS'ta Pull-to-Refresh: UIRefreshControl

UIRefreshControl, Pull-to-Refresh için standart iOS denetimidir ve iOS 6'dan beri kullanılabilir. UIRefreshControl, refreshControl özelliği (iOS 10+) aracılığıyla UITableViewController'a veya önceki sürümlerde tablonun bir alt görünümü olarak eklenir. Özelleştirilebilir renk (tintColor), title özelliği ve bir etiketle nitelikli dize (örneğin, "Güncelleniyor...") içeren yerleşik bir Spinner içerir.

UIRefreshControl, target-action mekanizması aracılığıyla çalışır: hareket etkinleştirildiğinde, belirtilen yöntem çağrılır (örneğin, refresh(_:)). Yöntemin içinde asenkron veri yükleme gerçekleştirilir. Tamamlandıktan sonra, animasyonla göstergeyi gizleyen endRefreshing() çağrılır. UIRefreshControl, hareket hassasiyetini otomatik olarak yönetir — yalnızca tablo üst konumdayken tetiklenir (contentOffset.y <= 0).

tintColor özelliği Spinner'ın rengini ayarlar. attributedTitle, tamamlandıktan sonra "2 dakika önce güncellendi" gibi metin gösterilmesini sağlar. iOS 10'dan itibaren UIRefreshControl, UIActivityIndicatorView veya kalıcı özel görünümler aracılığıyla özel animasyonları destekler. IT Sectr'de, tintColor'ı markaya göre yapılandırıyor ve attributedTitle aracılığıyla son güncelleme zamanını gösteriyoruz — bu, kullanıcıların verilere olan güvenini artırıyor.

Android'te Pull-to-Refresh: SwipeRefreshLayout

SwipeRefreshLayout, Android Support Library'den (androidx.swiperefreshlayout) kaydırılabilir içeriği (RecyclerView, NestedScrollView, ListView) sarmalayan ve Pull-to-Refresh işlevselliği ekleyen bir ViewGroup'tür. UIRefreshControl'ün (bir denetim olan, kap olmayan) aksine, SwipeRefreshLayout alt öğenin dokunma olaylarını kesen ve eşik aşıldığında yenileme göstergesini tetikleyen bir kaptır.

SwipeRefreshLayout, setColorSchemeColors() aracılığıyla renk özelleştirmesi olan dairesel bir Material Design ilerleme göstergesi kullanır. setOnRefreshListener yöntemi, asenkron yüklemenin gerçekleştirildiği onRefresh() geri çağırmasını ayarlar. Tamamlandıktan sonra, göstergeyi gizlemek için setRefreshing(false) çağrılır. Önemli: setRefreshing(true) onRefresh()'i tekrar çağırır — bu nedenle programlı olarak yenileme başlatmak için bir flag veya post yöntemi kullanın.

setProgressBackgroundColorSchemeResource özelliği göstergenin arka planını değiştirir. setSize(SwipeRefreshLayout.LARGE) Spinner boyutunu ayarlar. XML düzeninde, SwipeRefreshLayout RecyclerView'ı sarar: swipe_refresh_layout → recycler_view. Google I/O 2024'e göre, SwipeRefreshLayout içerik akışlı Android uygulamalarının %85'inde kullanılmaktadır. IT Sectr'de, asenkron olarak yüklenen listelere sahip tüm ekranları SwipeRefreshLayout ile sarıyoruz — bu, tüm Android sürümlerinde tutarlı bir UX sağlar.

Material Pull-to-Refresh (Android 12+)

Android 12'den (Material You) itibaren Google, material-1.6.0+ kitaplığından (Compose için androidx.compose.material3.pulltorefresh) yeni Material Pull-to-Refresh kullanılmasını önermektedir. Yeni API, yay animasyonu desteği ve duvar kağıdına dayalı uyarlanabilir renk ile animasyonlu bir gösterge kullanır. SwipeRefreshLayout, Android 12'nin altındaki sürümlerle uyumlu kalır.

En İyi Uygulamalar ve Yaygın Hatalar

Pull-to-Refresh uygulaması basit bir desendir, ancak kullanıcı deneyimini düşüren birkaç yaygın hata içerir. Bunları ve önleme yöntemlerini inceleyelim.

  • Çift yenileme — kullanıcı yükleme tamamlanmadan listeyi birkaç kez çekebilir. Çözüm: başlangıçta bir isRefreshing flag'i ayarlayın ve onRefresh() içinde kontrol edin. iOS'ta endRefreshing() yalnızca tamamlandıktan sonra çağrılır; UIRefreshControl'de hareket engelleme yerleşiktir.
  • Geri bildirim eksikliği — yükleme göstergesi, kullanıcı eşiği aştıktan sonra kesinlikle görünmelidir. Dokunmada hemen göstergeleri göstermeyin — kullanıcıların kafasını karıştırır. iOS ve Android bunu otomatik olarak yapar.
  • Yenileme süresini yok sayma — veriler 200 ms'de yenileniyorsa, kullanıcının güncellemeyi fark etmesi için gösterge en az 500 ms gösterilmelidir. UIRefreshControl'ün minimum animasyon süresi vardır; Android'te minimum görüntüleme süresi için Handler.postDelayed kullanın.
  • Klavye çakışması — açık klavye ile Pull-to-Refresh yanlışlıkla tetiklenebilir. iOS'ta view.endEditing(true) ve Android'te InputMethodManager.hideSoftInputFromWindow() ile hareket başladığında klavyeyi gizleyin.
  • Yenileme dışında kullanma — gezinme (sekme değiştirme, geri gitme) için Pull-to-Refresh kullanmayın. Bu, her iki platformun HIG'ini ihlal eder ve kullanıcıların kafasını karıştırır.

IT Sectr'de, test sunucusu günlüklerinde yinelenen istekler keşfettikten sonra her projeye isRefreshing kontrolü ekledik — hızlı parmaklı kullanıcıların yenilemeyi art arda 3 defaya kadar tetiklediği ortaya çıktı.

Swift ve Kotlin'de Kod Örnekleri

Örnek 1: iOS'ta UIRefreshControl (Swift)

Özel Spinner rengi ve nitelikli başlık ile UITableViewController'a Pull-to-Refresh ekler. Veri yüklendikten sonra gösterge gizlenir.

swift
import UIKit

class FeedTableViewController: UITableViewController {

    private var items: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.refreshControl = UIRefreshControl()
        refreshControl?.tintColor = .systemBlue
        refreshControl?.attributedTitle = NSAttributedString(
            string: "Yenilemek için çekin"
        )
        refreshControl?.addTarget(
            self,
            action: #selector(refreshData),
            for: .valueChanged
        )
    }

    @objc private func refreshData() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
            self.items = FeedService().fetchLatest()
            self.tableView.reloadData()
            self.refreshControl?.endRefreshing()
        }
    }
}

tableView.refreshControl özelliği (iOS 10+) UIRefreshControl'ü ayarlar. .valueChanged olayı ile addTarget, hareket etkinleştirildiğinde tetiklenir. endRefreshing() zorunludur — onsuz gösterge sonsuza kadar döner. Asenkron yükleme DispatchQueue.main.asyncAfter ile simüle edilmiştir — gerçek bir projede URLSession veya async/await kullanın.

Örnek 2: Android'te SwipeRefreshLayout (Kotlin)

Özel gösterge renkleriyle SwipeRefreshLayout içinde RecyclerView'ı sarar. onRefresh yüklemeyi başlatır ve tamamlandıktan sonra göstergeyi gizler.

kotlin
class FeedFragment : Fragment() {

    private var _binding: FragmentFeedBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentFeedBinding.inflate(inflater, container, false)

        binding.swipeRefreshLayout.setColorSchemeColors(
            resources.getColor(R.color.brand_blue, null),
            resources.getColor(R.color.brand_green, null)
        )
        binding.swipeRefreshLayout.setOnRefreshListener {
            loadData()
        }
        return binding.root
    }

    private fun loadData() {
        viewModelScope.launch {
            try {
                val result = repository.getLatestFeed()
                adapter.submitList(result)
            } finally {
                binding.swipeRefreshLayout.isRefreshing = false
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

setColorSchemeColors dönen Material Design göstergesinin renklerini ayarlar. isRefreshing = false, yükleme hatası durumunda bile göstergeyi gizlemek için finally bloğunda çağrılır. ViewModelScope.launch, parçacık yaşam döngüsü içinde bir coroutine yürütür — parçacık yok edildiğinde, coroutine otomatik olarak iptal edilir ve bellek sızıntılarını önler.

Örnek 3: SwiftUI .refreshable (iOS 15+)

Modern SwiftUI, List veya ScrollView'e otomatik olarak Pull-to-Refresh ekleyen .refreshable değiştiricisini sağlar.

swift
import SwiftUI

struct FeedView: View {

    @State private var items: [String] = []

    var body: some View {
        List(items, id: \.self) { item in
            Text(item)
        }
        .refreshable {
            items = await FeedService().fetchLatestAsync()
        }
    }
}

.refreshable değiştiricisi, Pull-to-Refresh'te yürütülen bir async kapanışı alır. SwiftUI otomatik olarak yenileme göstergesini gösterir ve gizler, durum yarışlarını yönetir (mevcut yenileme tamamlanana kadar yeni bir yenileme başlatmaz) ve animasyonu platforma uyarlar. iOS 15+ için, SwiftUI'de Pull-to-Refresh uygulamanın tercih edilen yoludur.

Sıkça Sorulan Sorular

Pull-to-Refresh SwiftUI'de çalışır mı?

Evet, SwiftUI, List veya ScrollView için .refreshable değiştiricisini sağlar ve iOS 15'ten itibaren kullanılabilir. Kapanış içinde asenkron veri yükleme kodu yürütülür. SwiftUI otomatik olarak yenileme göstergesini yönetir ve mevcut yükleme tamamlanana kadar tekrarlanan tetiklemeleri engeller — bu, yeni projeler için standart önerilen yaklaşımdır.

Çift yenileme nasıl önlenir?

isRefreshing flag'i kullanın: yükleme başlangıcında true, tamamlandıktan sonra false olarak ayarlayın. iOS'ta, endRefreshing() çağrılana kadar UIRefreshControl otomatik olarak tekrarlanan çağrıları engeller. Android'te, onRefresh() başlangıcında SwipeRefreshLayout.isRefreshing'i kontrol edin: true ise — return yapın. Bu, her hareket için bir istek garanti eder.

Pull-to-Refresh liste kaydırma ile çakışır mı?

UIRefreshControl ve SwipeRefreshLayout yalnızca liste üst konumdayken tetiklenir (contentOffset == 0). Mimari çakışmayı ortadan kaldırır: liste 1px bile kaydırıldığı sürece Pull-to-Refresh hareketi etkinleşmez. Bir çakışma olursa, Android'te nestedScrollingEnabled'i veya dokunmaları engelleyen özel GestureRecognizer'ların varlığını kontrol edin.

Özet

  • Pull-to-Refresh, Apple ve Google tarafından tüm mobil platformlarda standartlaştırılmış, aşağı çekme hareketiyle veri yenileme desenidir.
  • iOS'ta UIRefreshControl — target-action, tintColor, attributedTitle ve zorunlu endRefreshing() ile bir denetim.
  • Android'te SwipeRefreshLayout — setOnRefreshListener, setColorSchemeColors ve isRefreshing ile bir ViewGroup kapsayıcısı.
  • Material Pull-to-Refresh (Android 12+) — yay animasyonlu yeni API, yeni projeler için önerilir.
  • SwiftUI .refreshable — async kapanışlı bildirimsel değiştirici, iOS 15'ten itibaren kullanılabilir.
  • isRefreshing flag'i çift yenilemeyi önler — her iki platformda da zorunludur.
  • Pull-to-Refresh gezinme için değildir — yalnızca Material Design ve Apple HIG'ye göre içerik yenileme içindir.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun