Animating Apps With Flutter

Shubham

About The Author

A full stack software developer by the day and mobile app developer by night. Mentre non lavoro, amo cucinare e giocare ai giochi per PC.More aboutShubham↬

  • 14 min read
  • Apps,Animazione
  • Salvato per lettura offline
  • Condividi su Twitter, LinkedIn
Flutter fornisce un grande supporto di animazione per le app multipiattaforma. Questo articolo esplora il nuovo modo non convenzionale e più facile per aggiungere animazioni alle app. Cosa sono esattamente questi nuovi widget “Animazione e movimento” e come possiamo usarli per aggiungere animazioni semplici e complesse?

Le applicazioni per qualsiasi piattaforma sono apprezzate quando sono intuitive, di bell’aspetto e forniscono un feedback piacevole alle interazioni dell’utente. L’animazione è uno dei modi per fare proprio questo.

Flutter, un framework multipiattaforma, è maturato negli ultimi due anni per includere il supporto web e desktop. Si è guadagnato la reputazione che le applicazioni sviluppate con esso sono fluide e di bell’aspetto. Con il suo ricco supporto per l’animazione, il modo dichiarativo di scrivere l’UI, “Hot Reload,” e altre caratteristiche, è ora un framework multipiattaforma completo.

Se state iniziando con Flutter e volete imparare un modo non convenzionale di aggiungere animazione, allora siete nel posto giusto: esploreremo il regno dell’animazione e dei widget di movimento, un modo implicito di aggiungere animazioni.

Flutter è basato sul concetto di widget. Ogni componente visivo di un’app è un widget – pensate a loro come alle viste in Android. Flutter fornisce il supporto per l’animazione utilizzando una classe Animation, un oggetto “AnimationController” per la gestione, e “Tween” per interpolare la gamma di dati. Questi tre componenti lavorano insieme per fornire un’animazione fluida. Poiché questo richiede la creazione e la gestione manuale dell’animazione, è conosciuto come un modo esplicito di animare.

Ora lasciate che vi presenti i widget di animazione e movimento. Flutter fornisce numerosi widget che supportano intrinsecamente l’animazione. Non c’è bisogno di creare un oggetto di animazione o un qualsiasi controller, poiché tutta l’animazione è gestita da questa categoria di widget. Basta scegliere il widget appropriato per l’animazione richiesta e passare i valori delle proprietà del widget da animare. Questa tecnica è un modo implicito di animare.

Gerarchia di animazione in Flutter. (Grande anteprima)

Il grafico qui sopra stabilisce approssimativamente la gerarchia di animazione in Flutter, come sia l’animazione esplicita e implicita sono supportati.

Alcuni dei widget animati trattati in questo articolo sono:

  • AnimatedOpacity
  • AnimatedCrossFade
  • AnimatedAlign
  • AnimatedPadding
  • AnimatedSize
  • AnimatedPositioned.

Flutter non solo fornisce widget animati predefiniti, ma anche un widget generico chiamato AnimatedWidget, che può essere usato per creare widget personalizzati implicitamente animati. Come evidente dal nome, questi widget appartengono alla categoria dei widget animati e di movimento, e quindi hanno alcune proprietà comuni che ci permettono di rendere le animazioni molto più fluide e dall’aspetto migliore.

Lasciate che vi spieghi ora queste proprietà comuni, poiché saranno usate più avanti in tutti gli esempi.

  • duration
    La durata su cui animare i parametri.
  • reverseDuration
    La durata dell’animazione inversa.
  • curve
    La curva da applicare nell’animazione dei parametri. I valori interpolati possono essere presi da una distribuzione lineare o, se e quando specificato, possono essere presi da una curva.

Cominciamo il viaggio creando una semplice applicazione che chiameremo “Quoted”. Essa mostrerà una citazione casuale ogni volta che l’app si avvia. Due cose da notare: primo, tutte queste citazioni saranno hardcoded nell’applicazione; e secondo, nessun dato utente sarà salvato.

Nota: Tutti i file per questi esempi possono essere trovati su GitHub.

Iniziare

Flutter dovrebbe essere installato e avrete bisogno di una certa familiarità con il flusso di base prima di andare avanti. Un buon punto di partenza è “Using Google’s Flutter For Truly Cross-Platform Mobile Development”.

Crea un nuovo progetto Flutter in Android Studio.

Nuovo menu progetto Flutter in Android Studio. (Anteprima grande)

Questo aprirà un nuovo progetto guidato, dove è possibile configurare le basi del progetto.

Schermo di selezione del tipo di progetto Flutter. (Anteprima grande)

Nella schermata di selezione del tipo di progetto, ci sono vari tipi di progetti Flutter, ognuno dei quali si rivolge a uno scenario specifico. Per questo tutorial, scegliete Flutter Application e premete Next.

Ora dovete inserire alcune informazioni specifiche del progetto: il nome e il percorso del progetto, il dominio aziendale e così via. Date un’occhiata all’immagine qui sotto.

Schermo di configurazione dell’applicazione Flutter. (Anteprima grande)

Aggiungi il nome del progetto, il percorso di Flutter SDK, la posizione del progetto e una descrizione opzionale del progetto. Premere Avanti.

Schermo del nome del pacchetto di applicazione Flutter. (Anteprima grande)

Ogni applicazione (sia Android o iOS) richiede un nome unico del pacchetto. In genere, si usa l’inverso del dominio del proprio sito web; per esempio, com.google o com.yahoo. Premi Finish per generare un’applicazione Flutter funzionante.

Il progetto di esempio generato. (Anteprima grande)

Una volta generato il progetto, dovresti vedere la schermata mostrata sopra. Apri il file main.dart (evidenziato nello screenshot). Questo è il file principale dell’applicazione. Il progetto di esempio è completo di per sé, e può essere eseguito direttamente su un emulatore o un dispositivo fisico senza alcuna modifica.

Sostituisci il contenuto del file main.dart con il seguente frammento di codice:

import 'package:animated_widgets/FirstPage.dart';import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Animated Widgets', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, accentColor: Colors.redAccent, ), home: FirstPage(), ); }}

Questo codice pulisce il file main.dart aggiungendo solo semplici informazioni rilevanti per la creazione di una nuova applicazione. La classe MyApp restituisce un oggetto: un widget MaterialApp, che fornisce la struttura di base per creare app conformi al Material Design. Per rendere il codice più strutturato, crea due nuovi file dart all’interno della cartella lib: FirstPage.dart e Quotes.dart.

Il file FirstPage.dart. (Anteprima grande)

FirstPage.dart conterrà tutto il codice responsabile di tutti gli elementi visivi (widget) necessari alla nostra app Quoted. Tutta l’animazione è gestita in questo file.

Nota: Più avanti nell’articolo, tutti i frammenti di codice per ogni widget animato sono aggiunti a questo file come figli del widget Scaffold. Per maggiori informazioni, questo esempio su GitHub potrebbe essere utile.

Inizia aggiungendo il seguente codice a FirstPage.dart. Questo è il codice parziale dove altre cose saranno aggiunte in seguito.

import 'dart:math';import 'package:animated_widgets/Quotes.dart';import 'package:flutter/material.dart';class FirstPage extends StatefulWidget { @override State createState() { return FirstPageState(); }}class FirstPageState extends State with TickerProviderStateMixin { bool showNextButton = false; bool showNameLabel = false; bool alignTop = false; bool increaseLeftPadding = false; bool showGreetings = false; bool showQuoteCard = false; String name = ''; double screenWidth; double screenHeight; String quote; @override void initState() { super.initState(); Random random = new Random(); int quoteIndex = random.nextInt(Quotes.quotesArray.length); quote = Quotes.quotesArray; } @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( appBar: _getAppBar(), body: Stack( children: , ), ); }}

Il file Quotes.dart. (Anteprima grande)

Il file Quotes.dart contiene una lista di tutte le citazioni hardcoded. Un punto da notare qui è che la lista è un oggetto statico. Questo significa che può essere usato in altri posti senza creare un nuovo oggetto della classe Quotes. Questo è stato scelto per progettazione, dato che la lista di cui sopra agisce semplicemente come un’utilità.

Aggiungi il seguente codice a questo file:

class Quotes { static const quotesArray = ;}

Lo scheletro del progetto è ora pronto, quindi andiamo a dare un po’ più di corpo a Quoted.

AnimatedOpacity

Per dare un tocco personale all’applicazione, sarebbe bello sapere il nome dell’utente, quindi chiediamolo e mostriamo un pulsante next. Finché l’utente non inserisce il suo nome, questo pulsante è nascosto, e si mostrerà graziosamente quando viene dato un nome. Abbiamo bisogno di una sorta di animazione di visibilità per il pulsante, ma esiste un widget per questo? Sì, c’è.

Enter AnimatedOpacity. Questo widget si basa sul widget Opacity aggiungendo un supporto implicito all’animazione. Come lo usiamo? Ricordate il nostro scenario: abbiamo bisogno di mostrare un pulsante successivo con visibilità animata. Avvolgiamo il widget pulsante all’interno del widget AnimatedOpacity, inseriamo alcuni valori appropriati e aggiungiamo una condizione per innescare l’animazione – e Flutter può gestire il resto.

_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Animazione dell’opacità del pulsante successivo. (Anteprima grande)

Il widget AnimatedOpacity ha due proprietà obbligatorie:

  • opacity
    Un valore di 1 significa completamente visibile; 0 (zero) significa nascosto. Durante l’animazione, Flutter interpola i valori tra questi due estremi. Potete vedere come una condizione è posta per cambiare la visibilità, innescando così l’animazione.
  • child
    Il widget figlio che avrà la sua visibilità animata.

Dovreste ora capire come sia davvero semplice aggiungere l’animazione della visibilità con il widget implicito. E tutti questi widget seguono le stesse linee guida e sono facili da usare. Passiamo al prossimo.

AnimatedCrossFade

Abbiamo il nome dell’utente, ma il widget sta ancora aspettando un input. Nel passo precedente, quando l’utente inserisce il suo nome, visualizziamo il pulsante successivo. Ora, quando l’utente preme il pulsante, voglio smettere di accettare input e mostrare il nome inserito. Ci sono molti modi per farlo, naturalmente, ma forse possiamo nascondere il widget di input e mostrare un widget di testo non modificabile. Proviamo usando il widget AnimatedCrossFade.

Questo widget richiede due figli, poiché il widget sfuma tra loro in base a qualche condizione. Una cosa importante da tenere a mente mentre si usa questo widget è che entrambi i figli dovrebbero avere la stessa larghezza. Se l’altezza è diversa, allora il widget più alto viene tagliato dal basso. In questo scenario, due widget saranno usati come figli: input e label.

_getAnimatedCrossfade() { return AnimatedCrossFade( duration: Duration(seconds: 1), alignment: Alignment.center, reverseDuration: Duration(seconds: 1), firstChild: _getNameInputWidget(), firstCurve: Curves.easeInOut, secondChild: _getNameLabelWidget(), secondCurve: Curves.easeInOut, crossFadeState: showNameLabel ? CrossFadeState.showSecond : CrossFadeState.showFirst, );}
Cross-fading tra il widget input e quello name. (Anteprima grande)

Questo widget richiede un diverso insieme di parametri obbligatori:

  • crossFadeState
    Questo stato stabilisce quale figlio mostrare.
  • firstChild
    Specifica il primo figlio per questo widget.
  • secondChild
    Specifica il secondo figlio.

AnimatedAlign

A questo punto, l’etichetta del nome è posizionata al centro dello schermo. Sembrerà molto meglio in alto, dato che abbiamo bisogno del centro dello schermo per mostrare le virgolette. In poche parole, l’allineamento del widget dell’etichetta del nome dovrebbe essere cambiato da centrale a superiore. E non sarebbe bello animare questo cambiamento di allineamento insieme alla precedente animazione di dissolvenza incrociata? Facciamolo.

Come sempre, si possono usare diverse tecniche per ottenere questo risultato. Dato che il widget name label è già allineato al centro, animare il suo allineamento sarebbe molto più semplice che manipolare i valori superiore e sinistro del widget. Il widget AnimatedAlign è perfetto per questo lavoro.

Per iniziare questa animazione, è necessario un trigger. L’unico scopo di questo widget è quello di animare il cambio di allineamento, quindi ha solo poche proprietà: aggiungere un figlio, impostare il suo allineamento, innescare il cambio di allineamento, ed è tutto.

_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Animazione di allineamento del widget nome. (Anteprima grande)

Ha solo due proprietà obbligatorie:

  • child:
    Il bambino il cui allineamento sarà modificato.
  • alignment:
    Valore di allineamento richiesto.

Questo widget è davvero semplice ma i risultati sono eleganti. Inoltre, abbiamo visto come facilmente possiamo usare due diversi widget animati per creare un’animazione più complessa. Questa è la bellezza dei widget animati.

AnimatedPadding

Ora abbiamo il nome dell’utente in alto, animato in modo fluido senza molto sforzo, usando diversi tipi di widget animati. Aggiungiamo un saluto, “Ciao”, prima del nome. Aggiungendo un widget di testo con il valore “Ciao” in alto, questo si sovrapporrà al widget di testo del saluto, come nell’immagine qui sotto.

I widget del saluto e del nome si sovrappongono. (Anteprima grande)

E se il widget di testo del nome avesse del padding a sinistra? Aumentare il padding a sinistra funzionerà sicuramente, ma aspetta: possiamo aumentare il padding con qualche animazione? Sì, ed è quello che fa AnimatedPadding. Per rendere tutto questo molto più bello, facciamo in modo che il widget di testo dei saluti svanisca e che il padding del widget di testo del nome aumenti allo stesso tempo.

_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}

Siccome l’animazione di cui sopra dovrebbe avvenire solo dopo che il precedente allineamento animato è completo, abbiamo bisogno di ritardare l’attivazione di questa animazione. Divagando brevemente dall’argomento, questo è un buon momento per parlare di un meccanismo popolare per aggiungere ritardo. Flutter fornisce diverse tecniche di questo tipo, ma il costruttore Future.delayed è uno degli approcci più semplici, più puliti e più leggibili. Per esempio, per eseguire un pezzo di codice dopo 1 secondo:

Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});

Siccome la durata del ritardo è già nota (calcolata dalle durate delle animazioni precedenti), l’animazione può essere attivata dopo questo intervallo.

// Showing "Hi" after 1 second - greetings visibility trigger._showGreetings() { Future.delayed(Duration(seconds: 1), () { setState(() { showGreetings = true; }); });}// Increasing the padding for name label widget after 1 second - increase padding trigger._increaseLeftPadding() { Future.delayed(Duration(seconds: 1), () { setState(() { increaseLeftPadding = true; }); });}
Animazione del widget nome. (Anteprima grande)

Questo widget ha solo due proprietà obbligatorie:

  • child
    Il bambino all’interno di questo widget, al quale sarà applicato il padding.
  • padding
    La quantità di spazio da aggiungere.

AnimatedSize

Oggi, qualsiasi app che abbia qualche tipo di animazione includerà lo zoom in o out dei componenti visivi per catturare l’attenzione dell’utente (comunemente chiamata animazione di scala). Perché non usare la stessa tecnica qui? Possiamo mostrare all’utente una citazione motivazionale che ingrandisce dal centro dello schermo. Lasciate che vi presenti il widget AnimatedSize, che abilita gli effetti di zoom-in e zoom-out, controllati cambiando le dimensioni del suo figlio.

Questo widget è un po’ diverso dagli altri quando si tratta dei parametri richiesti. Abbiamo bisogno di quello che Flutter chiama un “Ticker”. Flutter ha un metodo per far sapere agli oggetti ogni volta che viene attivato un nuovo evento frame. Può essere pensato come qualcosa che invia un segnale che dice: “Fallo ora! … Fallo ora! … Fallo ora! …”

Il widget AnimatedSize richiede una proprietà – vsync – che accetta un fornitore di ticker. Il modo più semplice per ottenere un fornitore di ticker è aggiungere un Mixin alla classe. Ci sono due implementazioni di base del fornitore di ticker: SingleTickerProviderStateMixin, che fornisce un singolo ticker; e TickerProviderStateMixin, che ne fornisce diversi.

L’implementazione predefinita di un Ticker è usata per marcare i fotogrammi di un’animazione. In questo caso, viene impiegato quest’ultimo. Maggiori informazioni sui mixins.

// Helper method to create quotes card widget._getQuoteCardWidget() { return Card( color: Colors.green, elevation: 8.0, child: _getAnimatedSizeWidget(), );}// Helper method to create animated size widget and set its properties._getAnimatedSizeWidget() { return AnimatedSize( duration: Duration(seconds: 1), curve: Curves.easeInOut, vsync: this, child: _getQuoteContainer(), );}// Helper method to create the quotes container widget with different sizes._getQuoteContainer() { return Container( height: showQuoteCard ? 100 : 0, width: showQuoteCard ? screenWidth - 32 : 0, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text(quote, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),), ), ), );}// Trigger used to show the quote card widget._showQuote() { Future.delayed(Duration(seconds: 2), () { setState(() { showQuoteCard = true; }); });}
Animazione in scala del widget delle citazioni. (Anteprima grande)

Proprietà obbligatorie per questo widget:

  • vsync
    Il fornitore di ticker richiesto per coordinare l’animazione e i cambiamenti di frame.<
  • child
    Il figlio i cui cambiamenti di dimensione saranno animati.

L’animazione dello zoom in e zoom out è ora facilmente domabile.

AnimatedPositioned

Grande! Le citazioni zoomano dal centro per catturare l’attenzione dell’utente. Cosa succederebbe se scivolasse dal basso durante lo zoom? Proviamo. Questo movimento implica giocare con la posizione del widget delle citazioni e animare i cambiamenti delle proprietà di posizione. AnimatedPositioned è il candidato perfetto.

Questo widget fa automaticamente la transizione della posizione del bambino per una data durata ogni volta che la posizione specificata cambia. Un punto da notare: funziona solo se il suo widget genitore è uno “Stack”. Questo widget è abbastanza semplice e diretto da usare. Vediamo.

// Helper method to create the animated positioned widget.// With position changes based on "showQuoteCard" flag._getAnimatedPositionWidget() { return AnimatedPositioned( duration: Duration(seconds: 1), curve: Curves.easeInOut, child: _getQuoteCardWidget(), top: showQuoteCard ? screenHeight/2 - 100 : screenHeight, left: !showQuoteCard ? screenWidth/2 : 12, );}
Posizione con animazione in scala delle citazioni. (Anteprima grande)

Questo widget ha solo una proprietà obbligatoria:

  • child
    Il widget la cui posizione sarà modificata.

Se non ci si aspetta che la dimensione del bambino cambi insieme alla sua posizione, un’alternativa più performante a questo widget sarebbe SlideTransition.

Ecco la nostra animazione completa:

Tutti i widget animati insieme. (Anteprima grande)

Conclusione

Le animazioni sono parte integrante dell’esperienza utente. Le app statiche o le app con animazioni scadenti non solo abbassano la fidelizzazione degli utenti, ma anche la reputazione dello sviluppatore nel fornire risultati.

Oggi, la maggior parte delle app popolari hanno qualche tipo di animazione sottile per deliziare gli utenti. Un feedback animato alle richieste degli utenti può anche coinvolgerli ad esplorare di più. Flutter offre un sacco di caratteristiche per lo sviluppo multipiattaforma, tra cui un ricco supporto per animazioni fluide e reattive.

Flutter ha un grande supporto di plug-in che ci permette di utilizzare animazioni di altri sviluppatori. Ora che è maturato alla versione 1.9, con così tanto amore da parte della comunità, Flutter è destinato a migliorare in futuro. Direi che ora è un ottimo momento per imparare Flutter!

Leave a Reply