In questa guida completa su SwipeRefreshLayout Android vedrai come implementare il classico gesto di pull to refresh Android Java per aggiornare una lista Android con uno swipe verso il basso. Partiremo da cosa fa esattamente questo widget, perché è lo standard de facto nelle app moderne (Gmail, Instagram, Twitter, ecc.) e come integrarlo in modo corretto nella tua UI. Lavoreremo passo passo con Android Studio: dalla dipendenza Gradle alla configurazione del layout XML, fino al codice Java per gestire onRefresh(), setRefreshing(false) e il caricamento dei dati. Troverai esempi pratici con RecyclerView, personalizzazione dei colori dell’indicatore e un caso reale con chiamata API tramite Volley, così potrai riutilizzare rapidamente il codice nei tuoi progetti.

SwipeRefreshLayout Android pull to refresh

Cos’è SwipeRefreshLayout Android

SwipeRefreshLayout è un widget Android che aggiorna il contenuto con uno swipe verso il basso (swipe-to-refresh). Quando l’utente trascina la lista verso il basso, viene eseguito onRefresh(), che mostra un indicatore di caricamento circolare. Al termine dell’aggiornamento chiami setRefreshing(false) per nascondere l’indicatore.

In questo esempio usi SwipeRefreshLayout con una RecyclerView che mostra una semplice lista di colori.

SwipeRefreshLayout con RecyclerView

Il caso d’uso pi&ù comune di SwipeRefreshLayout Android è l’aggiornamento di una lista via pull to refresh Android Java. In pratica incapsuli una RecyclerView dentro lo SwipeRefreshLayout e, quando l’utente esegue lo swipe verso il basso, richiami i dati (da memoria locale o da rete) e aggiorni l’adapter. Questo pattern è ideale quando vuoi aggiornare la lista Android senza pulsanti o azioni aggiuntive nella toolbar.

Di seguito un esempio minimo, completo di XML e Java, per collegare lo swipe-to-refresh all’aggiornamento dei dati della RecyclerView:

XML: SwipeRefreshLayout con RecyclerView

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Java: onRefresh() per il Pull to Refresh Android

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private SwipeRefreshLayout swipeRefreshLayout;
    private RecyclerView recyclerView;
    private RecyclerViewAdapter adapter;
    private ArrayList<Pojo> data = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
        recyclerView = findViewById(R.id.recyclerView);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new RecyclerViewAdapter(this, data);
        recyclerView.setAdapter(adapter);

        // Listener per il gesto di pull-to-refresh
        swipeRefreshLayout.setOnRefreshListener(this);

        // Primo popolamento della lista
        loadData();
    }

    private void loadData() {
        data.clear();
        data.add(new Pojo("Elemento 1", "#FF0000"));
        data.add(new Pojo("Elemento 2", "#00FF00"));
        data.add(new Pojo("Elemento 3", "#0000FF"));
        adapter.notifyDataSetChanged();
    }

    @Override
    public void onRefresh() {
        // Qui puoi chiamare un'API o ricaricare i dati da locale
        loadData();

        // Nascondi lo spinner di caricamento
        swipeRefreshLayout.setRefreshing(false);
    }
}

Struttura del progetto SwipeRefreshLayout Android

  • activity_main.xml — layout principale con SwipeRefreshLayout e RecyclerView
  • recycler_list.xml — layout del singolo elemento della lista (MaterialCardView)
  • Pojo.java — modello dati per nome e codice colore
  • RecyclerViewAdapter.java — adattatore per RecyclerView (vedi tutorial RecyclerView)
  • MainActivity.java — logica principale con il listener di refresh

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/swipeRefresh">

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/recyclerView" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

recycler_list.xml

<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:cardBackgroundColor="#E0F7DA"
    app:cardElevation="20dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:cardCornerRadius="40dp"
    app:contentPadding="30dp"
    android:layout_margin="20dp"
    android:clickable="true"
    android:foreground="?android:attr/selectableItemBackground">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/name"
            android:textSize="20sp"
            android:padding="5dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/code"
            android:textSize="20sp"
            android:padding="5dp" />

    </LinearLayout>
</com.google.android.material.card.MaterialCardView>

Pojo.java

package com.example.swipeRefreshLayout;

public class Pojo {
    private String colorName;
    private String colorCode;

    public Pojo(String colorName, String colorCode) {
        this.colorName = colorName;
        this.colorCode = colorCode;
    }

    public String getColor() {
        return colorName;
    }

    public String getCode() {
        return colorCode;
    }
}

MainActivity.java

package com.example.swipeRefreshLayout;

import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    SwipeRefreshLayout swipeRefreshLayout;
    RecyclerView recyclerView;
    ArrayList<Pojo> arrayList;
    RecyclerViewAdapter recyclerViewAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listColor();

        recyclerView = findViewById(R.id.recyclerView);
        swipeRefreshLayout = findViewById(R.id.swipeRefresh);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerViewAdapter = new RecyclerViewAdapter(this, arrayList);
        recyclerView.setAdapter(recyclerViewAdapter);

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshListColor();
            }
        });
    }

    private void refreshListColor() {
        recyclerView.postDelayed(new Runnable() {
            @Override
            public void run() {
                recyclerView.smoothScrollToPosition(recyclerViewAdapter.getItemCount() - 1);
                swipeRefreshLayout.setRefreshing(false);
                Toast.makeText(MainActivity.this, "Lista aggiornata", Toast.LENGTH_SHORT).show();
            }
        }, 3000);
    }

    private void listColor() {
        arrayList = new ArrayList<>();
        arrayList.add(new Pojo("Red", "#FF0000"));
        arrayList.add(new Pojo("Yellow", "#FFFF00"));
        arrayList.add(new Pojo("Blue", "#0000FF"));
        arrayList.add(new Pojo("Green", "#008000"));
        arrayList.add(new Pojo("Orange", "#FFA500"));
        arrayList.add(new Pojo("Purple", "#EE82EE"));
    }
}

Come funziona il Pull to Refresh con SwipeRefreshLayout

  1. L’utente trascina la lista verso il basso e appare l’indicatore di caricamento.
  2. Il sistema chiama onRefresh().
  3. L’app aggiorna i dati (in questo esempio con un ritardo simulato di 3 secondi).
  4. Al termine chiami swipeRefreshLayout.setRefreshing(false) per nascondere l’indicatore.

Personalizzare i colori dello SwipeRefreshLayout Android

Per migliorare la UX e allineare lo swipe-to-refresh al tema grafico della tua app, puoi personalizzare sia i colori dell’animazione circolare sia il colore di sfondo dell’area di refresh. SwipeRefreshLayout espone due metodi chiave: setColorSchemeResources() per i colori dell’indicatore e setProgressBackgroundColorSchemeResource() per lo sfondo.

swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);

// Colori dell'indicatore (puoi passare pi&ù colori, ruoteranno durante il refresh)
swipeRefreshLayout.setColorSchemeResources(
        R.color.colorPrimary,
        R.color.colorPrimaryDark,
        R.color.colorAccent
);

// Colore di sfondo dell'area di caricamento
swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.white);

Ricorda che questi metodi accettano ID di risorsa (es. R.color.mio_colore) e non codici esadecimali diretti. Definisci quindi i colori in res/values/colors.xml e riutilizzali per mantenere coerenza grafica in tutta l’app.

SwipeRefreshLayout con chiamata API Volley

Un utilizzo tipico &egrave; combinare SwipeRefreshLayout Android con una chiamata API REST usando Volley. In questo modo, ogni gesto di pull-to-refresh scatena una richiesta di rete per aggiornare la lista con gli ultimi dati disponibili dal backend.

Nell’esempio seguente, quando l’utente esegue lo swipe, viene inviata una richiesta GET, la risposta JSON popola la RecyclerView e lo spinner viene nascosto in caso di successo o errore.

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private SwipeRefreshLayout swipeRefreshLayout;
    private RecyclerView recyclerView;
    private RecyclerViewAdapter adapter;
    private ArrayList<Pojo> data = new ArrayList<>();
    private RequestQueue requestQueue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
        recyclerView = findViewById(R.id.recyclerView);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new RecyclerViewAdapter(this, data);
        recyclerView.setAdapter(adapter);

        swipeRefreshLayout.setOnRefreshListener(this);

        // Inizializza Volley
        requestQueue = Volley.newRequestQueue(this);

        // Primo caricamento dati
        fetchDataFromApi();
    }

    private void fetchDataFromApi() {
        String url = "https://esempio.com/api/colors";

        swipeRefreshLayout.setRefreshing(true);

        StringRequest request = new StringRequest(Request.Method.GET, url,
                response -> {
                    // TODO: parsare la risposta JSON e popolare 'data'
                    data.clear();
                    // ... aggiungi nuovi Pojo alla lista ...
                    adapter.notifyDataSetChanged();
                    swipeRefreshLayout.setRefreshing(false);
                },
                error -> {
                    Toast.makeText(MainActivity.this, "Errore di rete", Toast.LENGTH_SHORT).show();
                    swipeRefreshLayout.setRefreshing(false);
                });

        requestQueue.add(request);
    }

    @Override
    public void onRefresh() {
        // Richiama l'API quando l'utente fa pull-to-refresh
        fetchDataFromApi();
    }
}

Questo pattern &egrave; ideale quando vuoi aggiornare la lista Android con dati sempre freschi provenienti dal server, mantenendo un’esperienza utente coerente con il comportamento delle principali app Android.

Errori comuni con SwipeRefreshLayout Android

Quando implementi SwipeRefreshLayout per la prima volta, &egrave; facile incappare in alcuni problemi ricorrenti. Ecco gli errori pi&ù frequenti e come risolverli.

  • Indicatore che non scompare mai — se non chiami setRefreshing(false) alla fine del caricamento (sia in caso di successo che di errore), lo spinner resta visibile all’infinito. Assicurati che la chiamata a setRefreshing(false) sia sempre eseguita in tutti i rami del codice (onResponse, onError, catch di eccezioni, ecc.).
  • onRefresh() non viene chiamato — verifica che la vista contenuta nello SwipeRefreshLayout sia scrollabile (es. RecyclerView) e che non intercetti il gesto di swipe. Controlla inoltre di aver impostato correttamente il listener con setOnRefreshListener(this) o con un’istanza anonima.
  • Swipe-to-refresh non visibile con toolbar o AppBarLayout — in layout complessi con CoordinatorLayout/AppBarLayout, posiziona lo SwipeRefreshLayout come contenitore diretto della RecyclerView (o della vista scrollabile) e non dell’intero CoordinatorLayout, per evitare conflitti di scroll.
  • Conflitti con paginazione o infinite scroll — se usi anche un caricamento “load more” a fine lista, evita che il refresh resetti in modo aggressivo il dataset. Gestisci in modo chiaro quando svuotare la lista (es. solo su refresh esplicito) e quando aggiungere nuovi elementi in coda.

Dipendenza Gradle per SwipeRefreshLayout Android

Per usare SwipeRefreshLayout nel tuo progetto, aggiungi questa dipendenza al file build.gradle del modulo app:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

FAQ SwipeRefreshLayout Android

Cos’è SwipeRefreshLayout Android?

SwipeRefreshLayout &egrave; un widget della libreria AndroidX progettato per implementare il gesto di swipe-to-refresh nelle app Android. Incapsula una vista scrollabile (come RecyclerView, ListView, NestedScrollView) e intercetta lo swipe verso il basso per mostrare un indicatore di caricamento circolare. Quando l’utente rilascia il dito, viene chiamato onRefresh(), dove puoi aggiornare i dati e poi nascondere lo spinner con setRefreshing(false).

Come usare SwipeRefreshLayout con RecyclerView?

Per usare SwipeRefreshLayout con RecyclerView devi racchiudere la RecyclerView dentro lo SwipeRefreshLayout nel file XML e impostare un listener di refresh nel codice Java. All’interno di onRefresh() esegui il caricamento dei dati (locale o remoto), aggiorni l’adapter con notifyDataSetChanged() e infine chiami swipeRefreshLayout.setRefreshing(false). In questo modo l’utente pu&ograve; aggiornare la lista Android semplicemente eseguendo il gesto di pull-to-refresh.

Come cambiare il colore dello spinner SwipeRefreshLayout?

Per cambiare il colore dello spinner di SwipeRefreshLayout usa il metodo setColorSchemeResources() passando uno o pi&ugrave; ID di colore definiti in colors.xml. Se vuoi modificare anche lo sfondo dell’area di caricamento, chiama setProgressBackgroundColorSchemeResource() con il colore desiderato. In questo modo puoi adattare lo swipe-to-refresh alla palette del tuo tema Material Design.

Come implementare pull to refresh Android Java per aggiornare una lista?

Per implementare il pull to refresh Android Java crea uno SwipeRefreshLayout nel layout XML e impostalo come contenitore della lista (RecyclerView o ListView). Nella tua Activity o Fragment registra un OnRefreshListener e, nel metodo onRefresh(), richiama una funzione che ricarica i dati (ad esempio da un’API con Volley o Retrofit). Una volta aggiornato l’adapter, chiudi l’animazione con setRefreshing(false) per indicare la fine del refresh all’utente.

Perché il mio SwipeRefreshLayout non funziona o non chiama onRefresh()?

Se onRefresh() non viene chiamato, controlla che la vista contenuta nello SwipeRefreshLayout sia effettivamente scrollabile, che non ci siano altre viste che intercettano lo swipe (ad esempio un ViewPager) e che il listener sia impostato correttamente con setOnRefreshListener(). Verifica anche che SwipeRefreshLayout sia il contenitore diretto della RecyclerView nel layout XML e che non sia annidato in modo errato dentro altri layout che gestiscono lo scroll.


Guide correlate

Per approfondire le liste, puoi seguire il tutorial su RecyclerView in Android e quello su ConstraintLayout in Android per gestire al meglio i layout complessi.

Se ti interessa lavorare con la barra superiore e il menu laterale, dai un’occhiata alle guide su Toolbar in Android e NavigationDrawer in Android.

Per animazioni avanzate e transizioni fluide tra stati diversi dell’interfaccia, puoi studiare MotionLayout in Android.

Per la gestione degli adapter e degli stati di caricamento, sono utili le lezioni su BaseAdapter in Android e su ProgressBar in Android.

Se vuoi una panoramica completa dell’ecosistema, puoi partire dalla pagina hub Guide Android Java, dove trovi tutti i tutorial organizzati per argomento.