Reagire alla scroll in Flutter con SliverAppBar e CustomScrollView
GuideIntermedio35 min Flutter 3.x

Reagire alla scroll in Flutter con SliverAppBar e CustomScrollView

Effetti di scroll con i Sliver

Se hai bisogno di un header che si comprime durante lo scroll, un'immagine di copertina con effetto parallasse o vuoi combinare header, griglie e liste in un'unica area scrollabile, i widget Sliver sono la soluzione idiomatica di Flutter.

In questo tutorial costruiremo una schermata di dettaglio con un SliverAppBar collassabile, contenuti misti e una lista performante, il tutto dentro un CustomScrollView.

Prerequisiti: conoscenza base di widget e layout in Flutter.

  1. 1

    Capire i Sliver e CustomScrollView

    Un Sliver è una porzione di area scrollabile. CustomScrollView è un widget che accetta una lista di sliver e li dispone lungo un unico asse di scroll condiviso.

    I principali sliver che useremo sono:

    • SliverAppBar: una AppBar che può espandersi, collassare e rimanere fissa (pinned) durante lo scroll.
    • SliverToBoxAdapter: incapsula un normale widget "box" (come Container o Column) dentro un contesto sliver.
    • SliverList e SliverGrid: versioni lazy di liste e griglie.

    La differenza chiave rispetto a ListView è che qui più sezioni diverse condividono lo stesso scroll fluido.

    Risultato atteso

    Hai chiara la differenza tra widget box e widget sliver e sai perché servono.

  2. 2

    Impostare lo scheletro con CustomScrollView

    Creiamo una nuova schermata StatelessWidget che usa CustomScrollView come corpo dello Scaffold. Per ora inseriamo solo un SliverAppBar di base per verificare che la struttura funzioni.

    import 'package:flutter/material.dart';
    
    class DetailScreen extends StatelessWidget {
      const DetailScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: CustomScrollView(
            slivers: const [
              SliverAppBar(
                title: Text('Dettaglio'),
                expandedHeight: 250,
              ),
            ],
          ),
        );
      }
    }

    Risultato atteso

    Compilando l'app vedi una AppBar alta 250px che occupa la parte superiore dello schermo.

  3. 3

    Configurare un SliverAppBar collassabile

    Ora rendiamo la AppBar interessante. Le proprietà chiave sono:

    • expandedHeight: altezza massima quando è espansa.
    • pinned: true: la barra resta visibile (collassata) in cima anche dopo lo scroll.
    • floating: se true, riappare appena si scrolla verso l'alto.
    • flexibleSpace: il contenuto che si espande/comprime, tipicamente un FlexibleSpaceBar.

    Usiamo FlexibleSpaceBar con un titolo e un'immagine di sfondo.

    SliverAppBar(
      expandedHeight: 260,
      pinned: true,
      stretch: true,
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('Monti del Trentino'),
        centerTitle: true,
        background: Image.network(
          'https://picsum.photos/id/1018/800/600',
          fit: BoxFit.cover,
        ),
        stretchModes: const [
          StretchMode.zoomBackground,
          StretchMode.blurBackground,
        ],
      ),
    )

    Risultato atteso

    Scrollando, l'immagine si comprime e il titolo si sposta gradualmente verso la AppBar collassata; tirando verso il basso l'immagine fa uno zoom (stretch).

  4. 4

    Aggiungere contenuto con SliverToBoxAdapter

    Dopo la AppBar vogliamo inserire un blocco di contenuto "normale" (una descrizione). Poiché CustomScrollView accetta solo sliver, incapsuliamo il nostro widget box dentro un SliverToBoxAdapter.

    Aggiungi questo sliver subito dopo il SliverAppBar nella lista slivers.

    SliverToBoxAdapter(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: const [
            Text(
              'Descrizione',
              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 8),
            Text(
              'Una raccolta dei sentieri piu belli del Trentino, '
              'con dislivelli, tempi di percorrenza e punti panoramici.',
            ),
          ],
        ),
      ),
    )

    Risultato atteso

    Sotto l'header appare un blocco di testo che scorre insieme al resto della schermata.

  5. 5

    Inserire una lista performante con SliverList

    Per elenchi lunghi usiamo SliverList con SliverChildBuilderDelegate, che costruisce gli elementi in modo lazy (solo quelli visibili), esattamente come ListView.builder.

    Il parametro childCount indica il numero di elementi; ometterlo crea una lista infinita.

    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return ListTile(
            leading: CircleAvatar(child: Text('${index + 1}')),
            title: Text('Sentiero n. ${index + 1}'),
            subtitle: const Text('Difficolta media - 3h'),
          );
        },
        childCount: 30,
      ),
    )

    Risultato atteso

    Sotto la descrizione compare una lista di 30 elementi che scorre in modo fluido nello stesso movimento dell'header.

  6. 6

    Aggiungere una griglia con SliverGrid

    Possiamo mixare anche una griglia nella stessa area di scroll. SliverGrid.builder usa un gridDelegate per definire il layout, ad esempio SliverGridDelegateWithFixedCrossAxisCount per un numero fisso di colonne.

    Inseriamo la griglia dopo la lista (o al posto suo, a seconda del design).

    SliverGrid.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 1.4,
      ),
      itemCount: 6,
      itemBuilder: (context, index) {
        return Card(
          child: Center(child: Text('Foto ${index + 1}')),
        );
      },
    )

    Risultato atteso

    Nella stessa schermata scrollabile compare una griglia a 2 colonne integrata con lista e header.

  7. 7

    Best practice e rifiniture

    Qualche accorgimento finale:

    • SliverPadding: usalo per aggiungere spaziatura attorno a un SliverList o SliverGrid (i normali Padding non funzionano tra sliver).
    • SliverFillRemaining: utile per riempire lo spazio residuo (es. stato vuoto centrato).
    • SliverSafeArea: gestisce le aree sicure in contesto sliver.
    • Preferisci sempre le versioni builder/delegate per liste lunghe: mantengono le performance grazie al lazy loading.

    Esempio di padding attorno alla lista precedente:

    SliverPadding(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      sliver: SliverList(
        delegate: SliverChildBuilderDelegate(
          (context, index) => ListTile(title: Text('Voce $index')),
          childCount: 10,
        ),
      ),
    )

    Risultato atteso

    Hai una schermata completa con header parallasse collassabile, contenuti misti, lista e griglia, tutto in un unico scroll fluido e performante.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!