Un'immersione profonda in PageView In Flutter (con transizioni personalizzate)

Esplorazione del widget PageView e creazione di transizioni di pagina personalizzate

Questo articolo è il settimo della serie di articoli che analizzano in dettaglio i widget integrati di Flutter.

  1. ListView / ScrollPhysics
  2. TextField
  3. FloatingActionButtons
  4. Widget Eroe
  5. Trasforma widget
  6. Trascinabili / DragTarget

In questo articolo, daremo un'occhiata a PageView e, successivamente, creeremo alcuni effetti personalizzati.

NOTA: ListView Deep Dive è un precursore di questo articolo. Gli elementi trattati in quell'articolo non saranno ripetuti poiché sono quasi gli stessi. Puoi leggere il mio articolo ListView qui

Esplorazione di PageView

Un PageView è un widget che genera pagine scorrevoli sullo schermo. Questo può essere un elenco fisso di pagine o una funzione builder che crea pagine ripetute. PageView agisce in modo simile a ListView nel senso di costruire elementi.

I tipi di PageView sono:

  1. Visualizzazione della pagina
  2. PageView.builder
  3. PageView.custom

PageView (costruttore predefinito)

Questo tipo accetta un elenco fisso di elementi secondari (pagine) e li rende scorrevoli.

Visualizzazione della pagina(
  figli:  [
    Contenitore(
      colore: Colors.pink,
    ),
    Contenitore(
      colore: Colors.cyan,
    ),
    Contenitore(
      color: Colors.deepPurple,
    ),
  ],
)

Il codice precedente produce il seguente risultato:

PageView.builder

Questo costruttore accetta una funzione itemBuilder e un itemCount simili a ListView.builder

PageView.builder (
  itemBuilder: (contesto, posizione) {
    return _buildPage ();
  },
  itemCount: listItemCount, // Può essere nullo
)

Come un ListView.builder, questo crea bambini su richiesta.

Se itemCount è impostato su null (non impostato), è possibile generare un elenco infinito di pagine.

Ad esempio, questo codice:

PageView.builder (
  itemBuilder: (contesto, posizione) {
    Return Container (
      colore: posizione% 2 == 0? Colors.pink: Colors.cyan,
    );
  },
)

Fornisce un elenco infinito di pagine con alternanza di colori rosa e ciano:

Nota: PageView.custom funziona allo stesso modo di ListView.custom (discusso nella precedente Deep Dive) e non ne discuteremo qui.

Orientamento

Tutti i tipi di visualizzazioni di pagina possono avere pagine a scorrimento orizzontale o verticale.

Visualizzazione della pagina(
  figli:  [
    // Aggiungi qui i bambini
  ],
  scrollDirection: Axis.vertical,
)

Il codice sopra ci dà:

PageSnapping

Lo snap alla pagina ci consente di mantenere la pagina a valori intermedi. Questo viene fatto disattivando l'attributo pageSnapping. In questo caso la pagina non scorrerà su una posizione intera e si comporterà come un normale ListView.

Visualizzazione della pagina(
  figli:  [
    // Aggiungi qui i bambini
  ],
  pageSnapping: false,
)

ScrollPhysics

Un PageView può avere un comportamento di scorrimento personalizzato allo stesso modo di ListViews. Non ripeteremo diversi tipi di ScrollPhysics poiché è discusso in ListView Deep Dive.

ScrollPhysics può essere modificato utilizzando il parametro di fisica:

Visualizzazione della pagina(
  figli:  [
    // Aggiungi qui i bambini
  ],
  fisica: BouncingScrollPhysics (),
)

Controllo di un PageView

Un PageView può essere controllato a livello di programmazione collegando un PageController.

// Metodo di generazione esterno
PageController controller = PageController ();
// Metodo di generazione interno
Visualizzazione della pagina(
  controller: controller,
  figli:  [
    // Aggiungi figli
  ],
)

La posizione di scorrimento, la pagina corrente, ecc. Possono essere verificate tramite il controller.

Nota: controller.currentPage restituisce un doppio valore. Ad esempio, quando si scorre la pagina, il valore passa gradualmente da 1 a 2 e non passa immediatamente a 2.

Aggiunta di transizioni personalizzate alle visualizzazioni di pagina

Parliamo dell'aggiunta di alcune transizioni personalizzate alle pagine utilizzando Transform + PageView. Questa parte utilizzerà ampiamente il widget Trasforma e ti consiglio di leggere uno dei molteplici articoli sul widget.

I miei consigli sarebbero il Deep Dive che ho scritto e l'articolo Transform di WM Leler.

Transizione 1

Il set up

Per prima cosa utilizziamo un PageView.builder di base

PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
  },
  itemCount: 10,
)

Per ora abbiamo 10 articoli.

Usiamo un PageController e una variabile che contiene il valore di currentPage.

Definizione di PageController e variabili:

PageController controller = PageController ();
var currentPageValue = 0.0;

Aggiornamento della variabile durante lo scorrimento di PageView.

controller.addListener (() {
  setState (() {
    currentPageValue = controller.page;
  });
});

Infine, costruiamo il PageView.

Ora, controlliamo per tre condizioni:

  1. Se la pagina è la pagina da cui si scorre
  2. Se la pagina è la pagina da scorrere
  3. Se la pagina è una pagina fuori dallo schermo
PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
    if (position == currentPageValue.floor ()) {
    } else if (position == currentAnimationValue.floor () + 1) {
      
    } altro {
      
    }
  },
  itemCount: 10,
)

Ora restituiamo la stessa pagina ma racchiusa in un widget Trasforma per trasformare le nostre pagine quando la facciamo scorrere.

PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
    if (position == currentPageValue.floor ()) {
      return Transform (
        transform: Matrix4.identity () .. rotateX (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } else if (position == currentPageValue.floor () + 1) {
      return Transform (
        transform: Matrix4.identity () .. rotateX (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } altro {
      Return Container (
        colore: posizione% 2 == 0? Colors.blue: Colors.pink,
        bambino: Centro (
          child: Text (
            "Pagina",
            stile: TextStyle (color: Colors.white, fontSize: 22.0),
          ),
        ),
      );
    }
  },
  itemCount: 10,
)

Qui, trasformiamo la pagina da cui si scorre e la pagina da cui si scorre.

currentPageValue.floor () ci dà la pagina a sinistra e

currentPageValue.floor () ci dà la pagina a destra

In questo esempio, ruotiamo la pagina sulla direzione X quando viene trascinata da un valore di currentPageValue meno l'indice in radianti. È possibile amplificare l'effetto moltiplicando questo valore.

Possiamo modificare questa trasformazione e l'allineamento della trasformazione per darci più tipi di nuove transizioni di pagina.

Transizione 2

Struttura del codice simile, solo con una trasformazione diversa:

PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
    if (position == currentPageValue.floor ()) {
      return Transform (
        trasforma: Matrix4.identity () .. rotateY (currentPageValue - position) .. rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } else if (position == currentPageValue.floor () + 1) {
      return Transform (
        trasforma: Matrix4.identity () .. rotateY (currentPageValue - position) .. rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } altro {
      Return Container (
        colore: posizione% 2 == 0? Colors.blue: Colors.pink,
        bambino: Centro (
          child: Text (
            "Pagina",
            stile: TextStyle (color: Colors.white, fontSize: 22.0),
          ),
        ),
      );
    }
  },
  itemCount: 10,
)

Qui ruotiamo attorno agli assi Y e Z.

Transizione 3

Questo è un tipo simile di transizione l'ultima volta ma con un effetto 3D aggiunto.

PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
    if (position == currentPageValue.floor ()) {
      return Transform (
        trasforma: Matrix4.identity () .. setEntry (3, 2, 0,004) .. rotateY (currentPageValue - position) .. rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } else if (position == currentPageValue.floor () + 1) {
      return Transform (
        trasforma: Matrix4.identity () .. setEntry (3, 2, 0,004) .. rotateY (currentPageValue - position) .. rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } altro {
      Return Container (
        colore: posizione% 2 == 0? Colors.blue: Colors.pink,
        bambino: Centro (
          child: Text (
            "Pagina",
            stile: TextStyle (color: Colors.white, fontSize: 22.0),
          ),
        ),
      );
    }
  },
  itemCount: 10,
)

La linea

..setEntry (3, 2, 0,004)

dà alle pagine un effetto tridimensionale.

Transizione 4

PageView.builder (
  controller: controller,
  itemBuilder: (contesto, posizione) {
    if (position == currentPageValue.floor ()) {
      return Transform (
        allineamento: Alignment.center,
        transform: Matrix4.identity () .. setEntry (3, 2, 0,001)
          ..rotateX (currentPageValue - position)
          ..rotateY (currentPageValue - position)
          ..rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } else if (position == currentPageValue.floor () + 1) {
      return Transform (
        allineamento: Alignment.center,
        transform: Matrix4.identity () .. setEntry (3, 2, 0,001)
          ..rotateX (currentPageValue - position)
          ..rotateY (currentPageValue - position)
          ..rotateZ (currentPageValue - position),
        child: Container (
          colore: posizione% 2 == 0? Colors.blue: Colors.pink,
          bambino: Centro (
            child: Text (
              "Pagina",
              stile: TextStyle (color: Colors.white, fontSize: 22.0),
            ),
          ),
        ),
      );
    } altro {
      Return Container (
        colore: posizione% 2 == 0? Colors.blue: Colors.pink,
        bambino: Centro (
          child: Text (
            "Pagina",
            stile: TextStyle (color: Colors.white, fontSize: 22.0),
          ),
        ),
      );
    }
  },
  itemCount: 10,
)

È possibile creare molti più tipi semplicemente modificando angoli di rotazione, assi, allineamenti e traslazioni.

App demo usando PageView

Per dimostrare una semplice app usando PageView in Flutter, ho creato un'app di esempio per studiare le parole per il GRE. Questa app visualizza e consente all'utente di salvare le parole più difficili utilizzando SQLite per salvarle. Ha anche sintesi vocale per pronunciare la parola stessa.

Puoi trovare questa app qui: https://github.com/deven98/FlutterGREWords

Questo è tutto per questo articolo! Spero vi sia piaciuto e lasciare qualche applauso se lo avete fatto. Seguimi per altri articoli di Flutter e commenta per qualsiasi feedback tu possa avere su questo articolo.

Sentiti libero di dare un'occhiata anche ai miei altri profili e articoli:

Alcuni dei miei altri articoli