Nello sviluppo di un'applicazione mobile moderna, non può mancare l'utilizzo dei Floating Action Button (FAB), ossia quei pulsanti circolari che permettono all'utente di eseguire un'azione primaria per quella schermata, e che generalmente troviamo in basso a destra nella schermata.
Alcuni esempi classici sono proprio l'inserimento di un nuovo elemento in una lista e l'invio di una nuova e-mail.
Insieme a questo componente, troviamo spesso anche l'utilizzo delle Snackbar, cioè un particolare widget introdotto dal Material Design, per dare un feedback all'utente sull'operazione compiuta o che verrà compiuta. La caratteristica tipica di questo componente è quella di comparire sullo schermo per un dato lasso di tempo e di non richiede un'interazione da parte dell'utente per chiuderlo.
In questa lezione, approfondiremo questi widget, analizzandone alcune personalizzazioni ed imparando a mostrare una Snackbar al tocco del FAB.
Le classi FloatingActionButton e SnackBar
Come di consueto, familiarizziamo con le principali proprietà di questi due widget prima di utilizzarli. Partiamo dal FloatingActionButton
.
Proprietà | Tipo Accettato | Descrizione |
---|---|---|
backgroundColor |
Color |
imposta il colore di riempimento del bottone. Di default questo colore è impostato a ThemeData.accentColor |
child |
Widget |
definisce l'elemento figlio del FAB e può essere un widget qualsiasi, come un'icona |
elevation |
double |
rappresenta il livello di elevazione scelto per il FAB. Di default il valore è impostato a 6 e non può essere negativo |
foregroundColor |
Color |
definisce il colore da usare per l'icona e il testo del FAB. Di default è impostata al valore ThemeData.accentIconTheme.color definito per il tema |
mini |
bool |
controlla la dimensione del bottone e se impostata a true diminuisce la dimensione del FAB |
onPressed |
VoidCallback |
definisce la callback da invocare quando l'utente clicca sul FAB |
shape |
ShapeBorder |
permette di definire una forma personalizzata per il FAB, come già visto in precedenza per altri widget |
Si tratta di proprietà semplici ma da tenere sempre ben a mente quando si lavora con i FloatingActionButton
, in quanto indispensabili per modificarne il comportamento. Inoltre, questo widget offre il costruttore FloatingActionButton.extended
per la creazione di un FAB avente la forma StadiumBorder
(di cui abbiamo già parlato nella lezione 15), con la possibilità di aggiungere un'icona e del testo.
Vediamo, invece, adesso le principali proprietà della SnackBar
fornita da Flutter.
Proprietà | Tipo Accettato | Descrizione |
---|---|---|
action |
SnackBarAction |
permette di definire un'azione che l'utente può compiere in base al messaggio scritto. Ad esempio, annullare l'operazione appena compiuta |
backgroundColor |
Color |
se specificata, definisce il colore della SnackBar. Di default il colore è impostato a ThemeData.snackBarTheme.backgroundColor |
behavior |
SnackBarBehavior |
definisce il comportamento e la posizione della SnackBar |
content |
Widget |
rappresenta il contenuto della SnackBar che può essere ad esempio un semplice testo o un Widget più elaborato |
duration |
Duration |
definisce per quanto tempo deve essere mostrata la SnackBar . Di default è a 4 sec |
elevation |
double |
rappresenta il livello di elevazione scelto per la SnackBar . Di default il valore è impostato a 6 e non può essere negativo |
shape |
ShapeBorder |
permette di definire una forma personalizzata per la SnackBar |
Queste proprietà sono tutto quello che ci occorre per utilizzare al meglio le SnackBar
.
Per ulteriori informazioni su questi widget e sulle altre proprietà fornite, si rimanda alla documentazione ufficiale e alle linee guida del Material Design.
Esempi pratici
Entriamo nel vivo della lezione con alcuni esempi utili per gestire e personalizzare i widget FloatingActionButton
e SnackBar
.
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 la proprietà floatingActionButton
che andremo a impostare di volta in volta con la definizione di un nuovo esempio di FloatingActionButton
.
class MyFAB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Lesson 21'),
),
body: Container(
child: Center(
child: Text("Default Scaffold Body"),
),
),
floatingActionButton: /*Set FAB here*/);
}
}
Come si può facilmente intuire, un FloatingActionButton
può essere definito solo tramite la proprietà floatingActionButton
offerta dal widget Scaffold
.
Partiamo da una semplice implementazione di FloatingActionButton
composto da un'icona e al cui tocco si genererà una stampa nel terminale. Per farlo, impostiamo un widget Icon
come figlio del FloatingActionButton
e implementiamo la callback
per la proprietà onPressed
affinché, ogni volta che l'utente tocca il bottone, verrà stampato un messaggio in console. Di seguito l'implementazione.
Widget _myBasicFAB() {
return FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
print("FAB clicked");
},
);
}
Impostando la proprietà floatingActionButton
del nostro Scaffold
con il metodo _myBasicFAB()
appena creato ed eseguendo l'applicazione avremo il seguente risultato.
Figura 136. Esempio di FloatingActionButton per a) Android b) iOS
Un altro esempio di facile realizzazione riguarda l'utilizzo del costruttore FloatingActionButton.extended
per la creazione di un FAB con la forma di uno StadiumBorder
. Vediamo insieme come.
Widget _myFABextended() {
return FloatingActionButton.extended(
onPressed: () {},
icon: Icon(Icons.email),
label: Text("New e-mail"),
);
}
Grazie a questo costruttore, abbiamo potuto creare un nuovo FloatingActionButton
che definisce un'icona della email e una label rappresentanti l'azione. Utilizzando questo metodo come valore della proprietà floatingActionButton
, otterremo il risultato in figura.
Figura 137. Esempio di utilizzo del costruttore FloatingActionButton.extended per a) Android b) iOS
Come si può notare, il FAB sarà composto dall'icona e dal testo dell'azione, che aiuterà l'utente a comprendere al meglio come utilizzare questo componente.
Abbiamo appreso nel corso di queste lezioni che la personalizzazione dei widget è un aspetto fondamentale nello sviluppo di un'app, in quanto l'applicazione deve essere uniforme e non presentare cambi di stile incoerenti. Pertanto, è possibile personalizzare anche il FloatingActionButton
. Ad esempio possiamo modificarne i colori attraverso le proprietà backgroundColor
e foregroundColor
, come segue.
Widget _myFABcustomColor() {
return FloatingActionButton(
onPressed: () {},
child: Icon(
Icons.email,
),
backgroundColor: Colors.amber,
foregroundColor: Colors.deepOrange,
);
}
In questo caso eseguendo l'applicazione, una volta aggiornata di conseguenza la proprietà floatingActionButton
, otterremo un FAB dove il background del bottone è color ambra e l'icona è arancione scuro, come mostrato di seguito.
Figura 138. Personalizzazione dei colori del FloatingActionButton per a) Android b) iOS
Attenzione però, se modificassimo il colore dei singoli elementi all'interno del FAB, come ad esempio il colore dell'icona, questa andrà a sovrascrivere sempre il colore definito dalla proprietà foregroundColor
. Ad esempio, definendo il colore dell'icona come segue
Widget _myFABColorVsFgColor() {
return FloatingActionButton(
onPressed: () {},
child: Icon(
Icons.email,
color: Colors.purple,
),
backgroundColor: Colors.amber,
foregroundColor: Colors.deepOrange,
);
}
otterremo che il colore arancione scuro della proprietà foregroundColor
venga sovrascritto dal colore viola definito in Icon
.
Figura 139. Esempio di sovrascrittura del colore foregroundColor per a) Android b) iOS
Un'altra personalizzazione utile è data dalla proprietà mini
, che permette di creare un FloatingActionButton
di dimensioni contenute. Ad esempio, impostando a true questa proprietà come nell'esempio seguente
Widget _myFABmini() {
return FloatingActionButton(
onPressed: () {},
child: Icon(Icons.email),
mini: true,
);
}
otterremo il risultato in figura.
Figura 140. Utilizzo della proprietà mini per a) Android b) iOS
Se invece non è la dimensione ciò che ci interessa modificare del FAB, bensì la sua forma, allora dobbiamo utilizzare la proprietà shape
definendo la forma che più ci interessa.
Ad esempio, immaginiamo di voler creare un FloatingActionButton
rettangolare con un bordo color ambra, allora dovremo definire la proprietà shape
tramite il widget RoundedRectangleBorder
, come segue.
Widget _myFABcustomShape() {
return FloatingActionButton(
onPressed: () {},
child: Icon(Icons.email),
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.amber, width: 5.0)),
);
}
Eseguendo l'applicazione, otterremo quanto mostrato in figura.
Figura 141. Personalizzazione della forma di un FloatingActionButton per a) Android b) iOS
Essendo un componente che va a sovrapporsi sul resto degli elementi della schermata è fondamentale che il FAB risulti rialzato rispetto agli elementi sottostanti come un listato. Per farlo, basta definire il valore più corretto per noi per la proprietà elevation
. Ad esempio:
Widget _myFABelevation() {
return FloatingActionButton(
onPressed: () {},
child: Icon(Icons.email),
elevation: 10,
);
}
in questo caso abbiamo impostato a 10 la proprietà elevation che, grazie all'ombra generata, farà risultare più in alto il FAB rispetto agli altri componenti, come si può notare dalla figura seguente.
Figura 142. Utilizzo della proprietà elevation per a) Android b) iOS
Infine, uno degli aspetti più importanti è proprio la posizione del FAB nella schermata con cui l'utente andrà ad interagire. A questo proposito, possiamo utilizzare la proprietà floatingActionButtonLocation
di Scaffold
, che accetta una delle proprietà definite per il widget FloatingActionButtonLocation
che forniscono una posizione precisa del FloatingActionButton
all'interno dello Scaffold
. Vediamo alcuni semplici esempi.
Per posizionare in basso al centro un FAB, basterà impostare la proprietà FloatingActionButtonLocation.centerFloat
come segue.
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
ottenendo quanto mostrato in figura.
Figura 143. Posizionamento del FAB al centro in basso nello Scaffold per a) Android b) iOS
Se invece volessimo posizionarlo in alto a destra dello Scaffold
, basterà impostare il valore FloatingActionButtonLocation.endTop
come segue:
floatingActionButtonLocation: FloatingActionButtonLocation.endTop,
ottenendo il risultato desiderato.
Figura 144. Posizionamento del FAB in alto a destra nello Scaffold per a) Android b) iOS
Queste ovviamente non sono le uniche posizioni possibili, ve ne sono altre che possono essere di aiuto nella realizzazione della vostra applicazione e sono consultabili tramite la documentazione ufficiale.
Ora che abbiamo compreso come definire un FloatingActionButton
, vediamo come possiamo definire e mostrare una SnackBar
quando il FAB viene toccato dall'utente.
Questa volta definiamo una nuova classe MyScaffoldFABwithSnackBar
che estende la classe StatelessWidget
e ha come scopo quello di creare un nuovo FloatingActionButton
, la cui proprietà onPressed
specifica una callback
che:
- definisce una
SnackBar
; - associa la
SnackBar
alloScaffold
.
Partiamo dalla definizione della SnackBar
e immaginiamo di voler creare una SnackBar
con le seguenti caratteristiche:
- il content sarà un semplice testo;
- l'action definirà una
SnackBarAction
che definirà la scritta CLOSE di colore bianco che, se premuta dall'utente, mostrerà un messaggio in console; - la forma della
SnackBar
avrà i bordi arrotondati e un contorno ambra; - il colore di background sarà viola;
- la
SnackBar
verrà mostrata per 2 secondi.
Per farlo definiamo quindi una variabile mySnackBar
di tipo SnackBar
come segue.
SnackBar mySnackBar = SnackBar(
content: Text('Hello!'),
action: SnackBarAction(
label: "CLOSE",
textColor: Colors.white,
onPressed: () {
debugPrint('clicking on CLOSE');
}),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
side: BorderSide(color: Colors.amber, width: 5.0)),
backgroundColor: Colors.purple,
duration: Duration(milliseconds: 2000),
);
In questo modo abbiamo definito la nostra SnackBar
, che può finalmente essere associata allo Scaffold
utilizzando la seguente riga di codice:
Scaffold.of(context).showSnackBar(mySnackBar)
Grazie a essa, siamo in grado di trovare lo Scaffold
di interesse nel widget tree e lo utilizziamo per mostrare la SnackBar
tramite il metodo showSnackBar
.
Mettendo quindi insieme i pezzi, definiamo la classe MyScaffoldFABwithSnackBar
come segue.
class MyScaffoldFABwithSnackBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: () {
SnackBar mySnackBar = SnackBar(
// . . .
);
Scaffold.of(context).showSnackBar(mySnackBar);
},
child: Icon(Icons.notifications),
);
}
}
Definita la classe, non ci resta che modificare la classe MyApp
per permettere la visualizzazione della SnackBar
. Modifichiamo poi la proprietà home affinché definisca uno Scaffold
con un floatingActionButton
.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// . . .
home: Scaffold(
floatingActionButton: MyScaffoldFABwithSnackBar(),
// . . .
),
);
}
}
Eseguendo l'applicazione otterremo il seguente risultato.
Figura 145a. Esempio di utilizzo si una SnackBar con FloatingActionButton per Android
Figura 145b. Esempio di utilizzo si una SnackBar con FloatingActionButton per iOS
Come possiamo vedere dall'animazione, quando l'utente clicca sul FAB viene:
- mostrata la
SnackBar
; - il FAB viene spostato in alto nella schermata per essere sempre disponibile all'utente senza essere coperto dalla notifica.
Qualora volessimo mostrare la SnackBar
in un punto diverso dalla posizione di default, possiamo utilizzare le proprietà behavior
ed elevation
del widget.
Ad esempio, possiamo definire le proprietà come segue:
behavior: SnackBarBehavior.floating,
elevation: 8,
In questo modo abbiamo dato un'elevazione di 8 e stabilito che SnackBar
debba essere mostrata al di sopra di altri widget.
Aggiungiamo le due proprietà alla SnackBar
definita in precedenza ed eseguiamo l'app, ottenendo i risultati in figura.
Figura 146a. Esempio di utilizzo della proprietà behavior per Android
Figura 146b. Esempio di utilizzo della proprietà behavior per iOS
Il codice di questa lezione è disponibile su GitHub.