Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 12 di 37
  • livello intermedio
Indice lezioni

Gestione degli assets e delle immagini

Imparare a gestire l'uso di immagini ed asset grafici sfruttando Flutter, framework per lo sviluppo di app mobile multipiattaforma.
Imparare a gestire l'uso di immagini ed asset grafici sfruttando Flutter, framework per lo sviluppo di app mobile multipiattaforma.
Link copiato negli appunti

Uno degli aspetti basilari nella creazione di un’applicazione mobile riguarda sicuramente la gestione degli assets (comunemente chiamate risorse) e delle immagini come la foto del profilo utente, foto provenienti dal web, o più semplicemente le icone di determinate azioni che l’utente può compiere.

In questa lezione focalizzeremo la nostra attenzione proprio sulla creazione degli asset e su come gestire le immagini caricate localmente nella nostra app.

La cartella assets e il pubspec.yaml

Un asset altro non è se non un file che viene rilasciato e distribuito con l’app ed è accessibile a runtime da quest’ultima per mostrare all’utente un’informazione.

I tipi comuni di risorse che possiamo trovare in un asset includono dati statici (ad esempio i file JSON), file di configurazione, font, icone e immagini tra i quali ritroviamo diversi formati, come ad esempio:

  • JPEG;
  • WebP;
  • PNG;
  • BMP;
  • GIF / GIF animate.

Differentemente da quanto si possa pensare, aggiungere gli asset ad un’app Flutter non è una prassi molto complessa.

Posizionandoci nella root del nostro progetto, aggiungiamo una nuova cartella come segue.

Tasto destro sul progetto -> New -> Directory

Nella finestra che comparirà inseriamo come nome della cartella la parola assets. Poiché questa cartella può contenere diverse tipologie di dato, è utile suddividere la cartella assets in sottocartelle. Analogamente a quanto appena fatto, aggiungiamo la cartella images e al suo interno carichiamo alcune immagini di esempio che potete trovare al seguente link.

Figura 63. Cartella assets contente alcune immagini in formato jpg (click per ingrandire)


Cartella assets contente alcune immagini in formato jpg

Per permettere a Flutter di identificare ed utilizzare la cartella assets è necessario modificare il file pubspec.yaml definito a livello della root del progetto modificando la sezione flutter come segue.

flutter:
  assets:
    - assets/images/

In questo modo Flutter identificherà il percorso assets/images/ come punto da cui recuperare tutte le immagini presenti in quel percorso. Nel dettaglio, durante la compilazione dell’app, Flutter collocherà questa cartella di assets in un archivio speciale chiamato asset bundle, a cui l'app accede durante l'esecuzione.

Qualora volessimo dare visibilità solo ad uno specifico file, basterà specificare il percorso a quel file. Ad esempio, immaginiamo che la nostra applicazione debba accedere solo a due immagini che si chiamano dog1.jpg e dog2.jpg. In questo caso, modificheremo la precedente dichiarazione come segue.

flutter:
  assets:
    - assets/images/dog1.jpg
    - assets/images/dog2.jpg

L’ordine con cui vengono dichiarati i percorsi non influenza la loro inclusione all’interno dell’assets bundle generato da Flutter.

Il widget Image

Per la visualizzazione di immagini e icone, Flutter offre il widget Image. Questo Widget mette a disposizione del programmatore diversi costruttori che possono essere utilizzati per inizializzarlo.

Costruttore Descrizione
Image l’immagine è caricata tramite un ImageProvider
Image.asset l’immagine viene caricata attraverso l’AssetBundle utilizzando una chiave che identifica univocamente la risorsa. In particolare, l’AssetBundle definisce le risorse come immagini e stringhe che possono essere utilizzate dall’app e sono state aggiunte in fase di compilazione nell’asset bundle
Image.network carica un’immagine disponibile in rete tramite la sua URL
Image.file l’immagine viene creata a partire da un oggetto File
Image.memory l’immagine viene caricata dalla memoria tramite l’utilizzo della classe Uint8List che definisce una lista di dimensioni predefinite a interi unsigned a 8-bit

Le proprietà

Come tutti i widget che abbiamo visto in queste lezioni, il widget Image fornisce un insieme di proprietà che, se definite, ne modificano il comportamento caratterizzandone il layout. Tra queste ritroviamo:

Proprietà Tipo Accettato Descrizione
alignment AlignmentGeometry definisce l’allineamento dell’immagine rispetto al nodo padre attraverso la definizione di un widget di tipo AlignmentGeometry come Alignment o AlignmentDirectional
color Color se definito, il colore scelto viene combinato con ogni pixel dell’immagine in base alla definizione della proprietà colorBlendMode
colorBlendMode BlendMode Questa proprietà definisce la modalità in cui applicare il colore scelto con la proprietà color ai pixel dell’immagine. Esistono diverse modalità che possono essere utilizzate, ognuna delle quali definisce un algoritmo che prende in ingresso due input:

  • source, che è l’immagine da disegnare;
  • destination, che rappresenta l’immagine su cui la source verrà composta.

Si può pensare alla destination come ad un background. Tra i diversi algoritmi, quello di default è srcIn. Si rimanda alla documentazione per maggiori informazioni.

filterQuality FilterQuality permette di definire il livello di qualità dell’immagine utilizzando le costanti definite da FilterQuality ognuna delle quali implementa una determinata funzione di interpolazione. Di default è impostata su FilterQuality.low
fit BoxFit indica come iscrivere l'immagine nello spazio assegnato durante il layout mediante la definizione di una delle proprietà offerte da BoxFit
height double definisce l’altezza dell’immagine
image ImageProvider l’immagine da mostrare utilizzando un ImageProvider invece dei costruttori come Image.network
repeat ImageRepeat definisce la modalità con cui riempire la porzione di layout non coperta dall’immagine. L’immagine caricata verrà ripetuta verticalmente e/o orizzontalmente utilizzando le proprietà della classe ImageRepeat. Il valore di default è ImageRepeat.noRepeat
semanticLabel String permette di definire una descrizione testuale per l’immagine per essere utilizzata da TalkBack di Android e VoiceOver di iOS
width double definisce la larghezza dell’immagine

Compreso, quindi, quali sono le principali proprietà offerte dal widget Image, vediamo adesso come utilizzarle con qualche esempio pratico.

Esempi pratici

Per iniziare creiamo un nuovo progetto come mostrato nella lezione 6 di questa guida e lasciando inalterati gli import, il metodo main() e la classe MyApp, cancelliamo il resto per aggiungere il seguente StatelessWidget composto da uno Scaffold per la definizione dell’AppBar e di una SingleChildScrollView (di cui abbiamo già parlato nella precedente lezione) che conterrà tutti i nostri esempi pratici di caricamento delle immagini.

class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Lesson 12 - Assets and Images'),
      ),
      body: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              //we will add our widgets here.
            ],
          )),
    );
  }
}

Modifichiamo infine la classe MyApp per impostare il widget appena creato come home.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // . . .
      home: MyPage(),
    );
  }
}

Ora siamo pronti per le nostre sperimentazioni.

Definiamo un insieme di costanti private che rappresentano il percorso alla cartella assets definita nel pubspec.yml e il percorso di ogni singola immagine.

const _PATH = "assets/images";
const _PIC01 = "$_PATH/sunset.jpg";
const _PIC02 = "$_PATH/dog1.jpg";
const _PIC03 = "$_PATH/dog2.jpg";
const _PIC04 = "$_PATH/fox.jpg";
const _PIC05 = "$_PATH/sping.jpg";

Questo passo renderà la scrittura del widget più compatta e intuitiva.

Creiamo adesso il nostro primo Image widget utilizzando il costruttore Image.asset che richiede in input il percorso al file come segue.

children: <Widget>[
  Container(
    constraints: BoxConstraints.expand(height: 300),
    alignment: Alignment.center,
    child: Image.asset(
      _PIC02,
      fit: BoxFit.cover,
    ),
  )
]

In questo modo abbiamo caricato dagli asset una nuova immagine posizionata al centro del nostro Container, specificando di caricare l’immagine _PIC02 e di impostare la proprietà fit in modalità cover, ossia rendendo l’immagine più piccola possibile ma riempendo allo stesso tempo il container.

Eseguendo l’applicazione otterremo il seguente risultato

Figura 64. Caricamento di un’immagine tramite il costruttore asset per a) Android e b) iOS (click per ingrandire)


Caricamento di un’immagine tramite il costruttore asset per a) Android e b) iOS

Analogamente a quanto appena fatto possiamo caricare un’immagine dagli asset usando l’AssetImage, che è un ImageProvider a tutti gli effetti. Creiamo quindi un nuovo container definendo il widget Image come segue.

children: <Widget>[
  // . . .
  Container(
    constraints: BoxConstraints.expand(height: 300),
    alignment: Alignment.center,
    child: Image(
      image: AssetImage(_PIC05),
      fit: BoxFit.cover,
    ),
  )
]

In questo modo non è necessario utilizzare il costruttore in quanto sfruttiamo la proprietà image per istanziare un nuovo AssetImage. Eseguendo l’applicazione, otterremo il seguente risultato.

Figura 65. Caricamento di un’immagine tramite AssetImage per a) Android e b) iOS (click per ingrandire)


Caricamento di un’immagine tramite AssetImage  per a) Android e b) iOS

Come si può notare sia che utilizziamo il costruttore Image.asset sia che utilizziamo l'AssetImage otterremo lo stesso risultato, ossia il caricamento dell'imamgine.Per semplicità, utilizzeremo nei prossimi esempi il costruttore Image.asset.

Vediamo ora come definire le proprietà height e width di Image

children: <Widget>[
  // . . .
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC01,
      height: 200,
      width: 200,
    ),
  )
],

Eseguendo l’applicazione otterremo il seguente risultato.

Figura 66. Caricamento di un’immagine tramite asset con dimensioni prefissate per a) Android e b) iOS (click per ingrandire)


Caricamento di un’immagine tramite asset con dimensioni prefissate per a) Android e b) iOS

Come possiamo notare, il ridimensionamento ha permesso a Flutter di scalare correttamente l’immagine senza generare distorsioni, ma allo stesso tempo ha lasciato degli spazi all’interno del container evidenziati dall sfondo blue-gray.

Per evitare questo effetto e far sì che l’immagine riempia appieno il container, possiamo ricorrere alla proprietà fit per definire la modalità con cui visualizzare l’immagine come la proprietà BoxFit.cover mostrata in precedenza. Oltre a questa, è possibile usare:

Proprietà Descrizione
fill riempie il contenitore distorcendo le proporzioni dell’immagine
fitWidth si assicura che l’intera larghezza dell’immagine sia mostrata e occupi il contenitore. Di conseguenza, l’immagine risulterà tagliata in altezza
fitHeight si assicura che l’intera altezza dell’immagine sia mostrata e occupi il contenitore. L’immagine verrà tagliata in larghezza se è più larga del widget padre, altrimenti verranno mostrati degli spazi laterali

Comprese queste tre proprietà vediamole in azione con un esempio chiarificatore e aggiungiamo i seguenti tre widget Image.

children: <Widget>[
  // . . .
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC01,
      fit: BoxFit.fill,
      height: 150,
      width: 150,
    ),
  ),
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC01,
      fit: BoxFit.fitWidth,
      height: 150,
      width: 150,
    ),
  ),
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC01,
      fit: BoxFit.fitHeight,
      height: 150,
      width: 150,
    ),
  )
]

Eseguendo l’applicazione otterremo il seguente risultato.

Figura 67. Caricamento di un’immagine tramite asset definendo la proprietà fit per a) Android e b) iOS (click per ingrandire)


Caricamento di una immagine tramite asset definendo la proprietà fit per a) Android e b) iOS

Oltre a queste proprietà, ve ne sono molte altre che possono essere utilizzate per decidere come mostrare le nostre immagini. Si rimanda alla documentazione di BoxFit per vedere ulteriori dettagli, mentre per alcuni esempi pratici si rimanda al codice di questa lezione.

Proviamo adesso ad utilizzare la proprietà repeat. Anche qui, ci sono diversi approcci tra cui repeatX, che ripeterà l’immagine orizzontalmente. Vediamo un esempio.

Container(
    constraints: BoxConstraints.expand(height: 50),
    margin: EdgeInsets.only(bottom: 15),
    child: Image.asset(
      _PIC03,
      repeat: ImageRepeat.repeatX,
      fit: BoxFit.contain,
    ),
  )

Eseguiamo ora l’app otterremo il seguente risultato.

Figura 68. Caricamento di un’immagine tramite asset ripetuta sul suo asse orizzontale per a) Android e b) iOS (click per ingrandire)


Caricamento di un’immagine tramite asset ripetuta sul suo asse orizzontale per a) Android e b) iOS

Altre due proprietà utili per l’applicazione di filtri semplici e veloci sono la combinazione di color e colorBlend. Ad esempio, immaginiamo di voler combinare il colore viola con l’immagine usando la modalità Color Dodge, il nostro codice sarà:

Container(
    child: Image.asset(
      _PIC04,
      color: Colors.purple,
      colorBlendMode: BlendMode.colorDodge,
    ),
  )

Tramite l’esecuzione dell’app otterremo il seguente risultato.

Figura 69. Caricamento di un’immagine tramite asset e definizione delle proprietà color e colorBlendMode per a) Android e b) iOS (click per ingrandire)


Caricamento di una immagine tramite asset e definizione delle proprietà color e colorBlendMode per a) Android e b) iOS

Ovviamente, questa è solo una delle molteplici modalità definite da BlendMode e si invita a consultare la documentazione ufficiale per saperne di più.

Vediamo infine la proprietà filterQuality che definisce il livello di qualità dell’immagine da mostrare. Confrontiamo ad esempio la stessa immagine caricata con qualità high e none come segue.

children: <Widget>[
  // . . .
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC05,
      filterQuality: FilterQuality.none,
    ),
  ),
  Container(
    color: Colors.blueGrey,
    child: Image.asset(
      _PIC05,
      filterQuality: FilterQuality.high,
    ),
  ),
]

A seguito dell’esecuzione dell’app, si può notare come l’immagine col filtro impostato a none abbia delle sgranature rispetto all’immagine sottostante con livello del filtro impostato ad high.

Figura 70. Caricamento di un’immagine tramite asset e definizione della proprietà filterQuality per a) Android e b) iOS (click per ingrandire)


Caricamento di un’immagine tramite asset e definizione della proprietà filterQuality per a) Android e b) iOS

Il codice di questa lezione è disponibile al seguente link.

Ti consigliamo anche