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 images link
Per permettere a Flutter di identificare ed utilizzare la cartella assets è necessario modificare il file pubspec.yaml
flutter
flutter:
assets:
- assets/images/
In questo modo Flutter identificherà il percorso assets/images/ asset bundle
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 dog2.jpg
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
|
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
Alignment
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:
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)
Analogamente a quanto appena fatto possiamo caricare un’immagine dagli asset usando l’AssetImage
ImageProvider
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)
Come si può notare sia che utilizziamo il costruttore Image.asset
AssetImage
Image.asset
Vediamo ora come definire le proprietà height
width
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)
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
BoxFit.cover
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)
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
questa lezione
Proviamo adesso ad utilizzare la proprietà repeat
repeatX
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)
Altre due proprietà utili per l’applicazione di filtri semplici e veloci sono la combinazione di color
colorBlend
Color Dodge
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)
Ovviamente, questa è solo una delle molteplici modalità definite da BlendMode
documentazione ufficiale
Vediamo infine la proprietà filterQuality
high
none
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
high
Figura 70. Caricamento di un’immagine tramite asset e definizione della proprietà filterQuality per a) Android e b) iOS (click per ingrandire)
Il codice di questa lezione è disponibile al seguente link
Ti consigliamo anche
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 |