Pull-to-Refresh: Grundlagen, RefreshControl und UIRefreshControl

Autor: IT Sectr Veröffentlicht: 2026-02-27 Lesezeit: 8 Min.
Pull-to-Refresh ist ein mobiles UI-Muster, bei dem der Benutzer die Liste mit dem Finger nach unten zieht und so das Laden neuer Daten auslöst. Die Geste wird von einem visuellen Indikator begleitet — einem rotierenden Spinner oder animierten Symbol — der nach Abschluss des Ladevorgangs verschwindet. Laut UX-Analyse von Apple HIG ist Pull-to-Refresh seit seiner Einführung in Tweetie (2008) und der anschließenden Standardisierung durch Apple und Google zum Standardmechanismus für die Aktualisierung von Inhalten in Nachrichtenfeeds, sozialen Netzwerken und E-Mail-Clients geworden.

Wichtige Punkte

  • Pull-to-Refresh ist eine Geste, bei der die Liste nach unten gezogen wird, um Daten zu aktualisieren, begleitet von einem visuellen Ladeindikator.
  • In iOS wird UIRefreshControl (iOS 6+) verwendet, das über die refreshControl-Eigenschaft zu UITableViewController oder UIScrollView hinzugefügt wird.
  • In Android wird SwipeRefreshLayout (aus der Support Library) verwendet — ein ViewGroup-Wrapper für RecyclerView oder NestedScrollView.
  • Beide APIs unterstützen die Anpassung von Farben, Indikatoren und Callbacks über Listener (iOS: UIRefreshControl.target-action, Android: setOnRefreshListener).
  • Pull-to-Refresh wird automatisch blockiert, wenn sich die Liste nicht in der obersten Position befindet — ein Konflikt mit dem Scrollen ist architektonisch ausgeschlossen.

Was ist Pull-to-Refresh?

Pull-to-Refresh ist ein Benutzeroberflächenmuster, bei dem der Benutzer eine Liste oder einen scrollbaren Bereich nach unten zieht (pull down), um den Inhalt zu aktualisieren. Optisch wird die Geste von einem Ladeindikator (Spinner) begleitet, der oben auf dem Bildschirm erscheint und nach dem Empfang der Daten verschwindet. Das Muster wurde durch die Tweetie-App für das iPhone (2008) populär gemacht und anschließend von Apple (iOS 6 — UIRefreshControl) und Google (Android Support Library — SwipeRefreshLayout) standardisiert.

Aus technischer Sicht ist Pull-to-Refresh eine Kombination aus Schwenken (Verfolgung der Fingerbewegung) und einem Auslöser beim Erreichen eines Schwellenwerts. Der Benutzer zieht die Liste nach unten, überwindet einen Widerstand (resistives Overscroll), und nach Überschreiten des Schwellenwerts (~80px auf iOS, ~64dp auf Android) beginnen die Indikatoranimation und das asynchrone Laden. Lässt der Benutzer den Finger vor dem Schwellenwert los, kehrt die Liste ohne Aktualisierung in ihre ursprüngliche Position zurück.

Gemäß den Material Design Guidelines sollte Pull-to-Refresh nicht für die Navigation oder das Umschalten von Tabs verwendet werden — sein einziger Zweck ist die Datenaktualisierung. Bei IT Sectr verwenden wir Pull-to-Refresh in Nachrichtenfeeds, Bestelllisten und Chats, wo die Aktualität der Daten für die Benutzererfahrung entscheidend ist.

Pull-to-Refresh in iOS: UIRefreshControl

UIRefreshControl ist das standardmäßige iOS-Steuerelement für Pull-to-Refresh, verfügbar seit iOS 6. UIRefreshControl wird über die refreshControl-Eigenschaft (iOS 10+) zu UITableViewController oder als Subview der Tabelle in früheren Versionen hinzugefügt. Es enthält einen integrierten Spinner mit anpassbarer Farbe (tintColor), title-Attribut und einer attributed string mit einer Beschriftung (z. B. "Aktualisieren...").

UIRefreshControl funktioniert über den Target-Action-Mechanismus: Wenn die Geste aktiviert wird, wird die angegebene Methode aufgerufen (z. B. refresh(_:)). Innerhalb der Methode wird asynchrones Laden von Daten durchgeführt. Nach Abschluss wird endRefreshing() aufgerufen, das den Indikator mit einer Animation ausblendet. UIRefreshControl verwaltet automatisch die Gestenempfindlichkeit — es wird nur ausgelöst, wenn sich die Tabelle in der oberen Position befindet (contentOffset.y <= 0).

Die Eigenschaft tintColor legt die Spinnerfarbe fest. attributedTitle ermöglicht die Anzeige von Text wie "Vor 2 Minuten aktualisiert" nach Abschluss. Seit iOS 10 unterstützt UIRefreshControl benutzerdefinierte Animationen über UIActivityIndicatorView oder persistente benutzerdefinierte Ansichten. Bei IT Sectr konfigurieren wir tintColor entsprechend der Marke und zeigen die letzte Aktualisierungszeit über attributedTitle an — dies erhöht das Vertrauen der Benutzer in die Daten.

Pull-to-Refresh in Android: SwipeRefreshLayout

SwipeRefreshLayout ist ein ViewGroup aus der Android Support Library (androidx.swiperefreshlayout), das scrollbare Inhalte (RecyclerView, NestedScrollView, ListView) umschließt und Pull-to-Refresh-Funktionalität hinzufügt. Im Gegensatz zu UIRefreshControl (das ein Steuerelement und kein Container ist) ist SwipeRefreshLayout ein Container, der Touch-Ereignisse des Kindelements abfängt und den Aktualisierungsindikator auslöst, wenn der Schwellenwert überschritten wird.

SwipeRefreshLayout verwendet einen kreisförmigen Material Design-Fortschrittsindikator mit Farbanpassung über setColorSchemeColors(). Die Methode setOnRefreshListener legt den onRefresh()-Callback fest, in dem das asynchrone Laden durchgeführt wird. Nach Abschluss wird setRefreshing(false) aufgerufen, um den Indikator auszublenden. Wichtig: setRefreshing(true) löst onRefresh() erneut aus — verwenden Sie daher für den programmgesteuerten Start der Aktualisierung ein Flag oder eine post-Methode.

Die Eigenschaft setProgressBackgroundColorSchemeResource ändert den Hintergrund des Indikators. setSize(SwipeRefreshLayout.LARGE) legt die Spinnergröße fest. Im XML-Layout umschließt SwipeRefreshLayout RecyclerView: swipe_refresh_layout → recycler_view. Laut Google I/O 2024 wird SwipeRefreshLayout in 85 % der Android-Apps mit Inhaltsfeeds verwendet. Bei IT Sectr umschließen wir alle Bildschirme mit asynchron geladenen Listen in SwipeRefreshLayout — dies bietet eine einheitliche Benutzererfahrung auf allen Android-Versionen.

Material Pull-to-Refresh (Android 12+)

Ab Android 12 (Material You) empfiehlt Google die Verwendung des neuen Material Pull-to-Refresh aus der Bibliothek material-1.6.0+ (androidx.compose.material3.pulltorefresh für Compose). Die neue API verwendet einen animierten Indikator mit Unterstützung für Spring-Animationen und adaptive Farbe basierend auf dem Hintergrundbild. SwipeRefreshLayout bleibt für Versionen unter Android 12 kompatibel.

Best Practices und häufige Fehler

Pull-to-Refresh ist ein einfach zu implementierendes Muster, enthält jedoch mehrere häufige Fehler, die die Benutzererfahrung beeinträchtigen. Sehen wir sie uns an und wie man sie vermeidet.

  • Doppelte Aktualisierung — der Benutzer kann die Liste mehrmals ziehen, bevor der Ladevorgang abgeschlossen ist. Lösung: Setzen Sie ein isRefreshing-Flag zu Beginn und prüfen Sie es in onRefresh(). In iOS wird endRefreshing() erst nach Abschluss aufgerufen; die Gestenblockierung in UIRefreshControl ist integriert.
  • Fehlendes Feedback — der Ladeindikator sollte erst erscheinen, nachdem der Benutzer den Schwellenwert überschritten hat. Zeigen Sie den Indikator nicht sofort bei Berührung an — das verwirrt die Benutzer. iOS und Android erledigen dies automatisch.
  • Ignorieren der Aktualisierungsdauer — wenn Daten in 200 ms aktualisiert werden, sollte der Indikator mindestens 500 ms angezeigt werden, damit der Benutzer die Aktualisierung bemerkt. UIRefreshControl hat eine minimale Animationsdauer; in Android verwenden Sie Handler.postDelayed für eine minimale Anzeigezeit.
  • Konflikt mit der Tastatur — bei geöffneter Tastatur kann Pull-to-Refresh versehentlich ausgelöst werden. Blenden Sie die Tastatur aus, wenn die Geste beginnt, über view.endEditing(true) in iOS und InputMethodManager.hideSoftInputFromWindow() in Android.
  • Verwendung für Nicht-Aktualisierungszwecke — verwenden Sie Pull-to-Refresh nicht für die Navigation (Tab-Wechsel, Zurückgehen). Dies verstößt gegen die HIG beider Plattformen und desorientiert die Benutzer.

Bei IT Sectr haben wir die isRefreshing-Prüfung in jedem Projekt hinzugefügt, nachdem wir doppelte Anfragen in den Testserver-Logs entdeckt hatten — es stellte sich heraus, dass Benutzer mit schnellen Fingern die Aktualisierung bis zu 3 Mal hintereinander auslösten.

Codebeispiele in Swift und Kotlin

Beispiel 1: UIRefreshControl in iOS (Swift)

Fügt UITableViewController Pull-to-Refresh mit benutzerdefinierter Spinnerfarbe und attributed title hinzu. Nach dem Laden der Daten wird der Indikator ausgeblendet.

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: "Zum Aktualisieren ziehen"
        )
        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()
        }
    }
}

Die Eigenschaft tableView.refreshControl (iOS 10+) setzt UIRefreshControl. addTarget mit dem .valueChanged-Ereignis wird ausgelöst, wenn die Geste aktiviert wird. endRefreshing() ist obligatorisch — ohne ihn dreht sich der Indikator unendlich weiter. Das asynchrone Laden wird mit DispatchQueue.main.asyncAfter simuliert — in einem echten Projekt verwenden Sie URLSession oder async/await.

Beispiel 2: SwipeRefreshLayout in Android (Kotlin)

Umschließt RecyclerView in SwipeRefreshLayout mit benutzerdefinierten Indikatorfarben. onRefresh startet das Laden und blendet den Indikator nach Abschluss aus.

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 legt die Farben des rotierenden Material Design-Indikators fest. isRefreshing = false wird im finally-Block aufgerufen, um den Indikator auch bei Ladefehlern auszublenden. ViewModelScope.launch führt eine Coroutine innerhalb des Fragmentlebenszyklus aus — wenn das Fragment zerstört wird, wird die Coroutine automatisch abgebrochen, um Speicherlecks zu verhindern.

Beispiel 3: SwiftUI .refreshable (iOS 15+)

Modernes SwiftUI bietet den Modifikator .refreshable, der automatisch Pull-to-Refresh zu List oder ScrollView hinzufügt.

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()
        }
    }
}

Der Modifikator .refreshable nimmt einen async-Closure entgegen, der bei Pull-to-Refresh ausgeführt wird. SwiftUI zeigt und verbirgt automatisch den Aktualisierungsindikator, verwaltet Race Conditions (startet keine neue Aktualisierung, bis die aktuelle abgeschlossen ist) und passt die Animation an die Plattform an. Für iOS 15+ ist dies die bevorzugte Methode zur Implementierung von Pull-to-Refresh in SwiftUI.

Häufig gestellte Fragen

Funktioniert Pull-to-Refresh in SwiftUI?

Ja, SwiftUI bietet den .refreshable-Modifikator für List oder ScrollView, verfügbar seit iOS 15. Innerhalb des Closures wird asynchroner Datenladecode ausgeführt. SwiftUI verwaltet automatisch den Aktualisierungsindikator und blockiert wiederholte Auslösungen, bis der aktuelle Ladevorgang abgeschlossen ist — dies ist der empfohlene Standardansatz für neue Projekte.

Wie verhindert man eine doppelte Aktualisierung?

Verwenden Sie ein isRefreshing-Flag: setzen Sie es zu Beginn des Ladens auf true und nach Abschluss auf false. In iOS blockiert UIRefreshControl automatisch wiederholte Aufrufe, bis endRefreshing() aufgerufen wird. In Android prüfen Sie SwipeRefreshLayout.isRefreshing am Anfang von onRefresh(): wenn true — return. Dies garantiert eine Anfrage pro Geste.

Konflikt Pull-to-Refresh mit dem Scrollen der Liste?

UIRefreshControl und SwipeRefreshLayout werden nur ausgelöst, wenn sich die Liste in der oberen Position befindet (contentOffset == 0). Die Architektur schließt Konflikte aus: Solange die Liste auch nur um 1px gescrollt ist, wird die Pull-to-Refresh-Geste nicht aktiviert. Tritt ein Konflikt auf, überprüfen Sie nestedScrollingEnabled in Android oder das Vorhandensein benutzerdefinierter GestureRecognizer, die Berührungen abfangen.

Zusammenfassung

  • Pull-to-Refresh ist ein Datenaktualisierungsmuster durch Nach-unten-Ziehen, standardisiert von Apple und Google auf allen mobilen Plattformen.
  • UIRefreshControl in iOS — ein Steuerelement mit Target-Action, tintColor, attributedTitle und obligatorischem endRefreshing().
  • SwipeRefreshLayout in Android — ein ViewGroup-Container mit setOnRefreshListener, setColorSchemeColors und isRefreshing.
  • Material Pull-to-Refresh (Android 12+) — eine neue API mit Spring-Animation, empfohlen für neue Projekte.
  • SwiftUI .refreshable — ein deklarativer Modifikator mit async-Closure, verfügbar seit iOS 15.
  • Das isRefreshing-Flag verhindert doppelte Aktualisierungen — auf beiden Plattformen obligatorisch.
  • Pull-to-Refresh ist nicht für die Navigation gedacht — nur für Inhaltsaktualisierungen gemäß Material Design und Apple HIG.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch