Nella lezione precedente abbiamo preso confidenza con le classi MaterialApp
e ThemeData
per la definizione di temi. In questa lezione ci focalizzeremo su alcuni esempi pratici per definire ed utilizzare i temi all’interno della nostra applicazione.
Esempi pratici
Ora che abbiamo familiarizzato con questi Widget
analizzandone le proprietà, passiamo alla pratica e iniziamo a personalizzare la nostra applicazione. Per farlo partiamo con la creazione di una nuova app come illustrato nella lezione 6 di questa guida e, a differenza delle altre lezioni, lasciamo il codice inalterato in quanto andremo a lavorare proprio sull’applicazione di esempio fornita da questo framework. Riportiamo di seguito la struttura della classe MyApp
.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: /*add here yout theme*/,
home: MyHomePage(title: 'Lesson 23'),
);
}
Come possiamo notare all’interno del metodo build ritroviamo il widget MaterialApp che di base definisce:
- un titolo;
- un tema;
- il widget per la home della nostra applicazione.
Di nostro interesse, infatti, è proprio la proprietà theme
per cui andremo a definire all’interno della classe MyApp
diversi metodi per impostare un nuovo tema per la nostra applicazione.
Partiamo da un semplice esempio che ci permette di impostare su dark
il tema della nostra applicazione usando i colori preimpostati.
Per farlo, impostiamo la proprietà theme come segue.
theme: ThemeData.dark(),
ottenendo il seguente risultato una volta avviata l’applicazione.
Invocando semplicemente il metodo dark()
di ThemeData
abbiamo cambiato completamente il tema della nostra applicazione da chiaro a scuro, ma siamo comunque legati a colori e stili preimpostati per noi.
Vediamo quindi come possiamo definire un tema globale andando a creare un nuovo widget ThemeData
in cui specifichiamo noi stessi cosa vogliamo modificare del tema.
Immaginiamo di voler modificare nella nostra applicazione:
- la famiglia di font per usarne uno specifico;
- il colore primario e secondario;
- un tema personalizzato per i testi dell’applicazione.
Per farlo creiamo un nuovo metodo che si occuperà di creare e di restituire un nuovo ThemeData
.
ThemeData _myCustomThemeData() {
return ThemeData(
fontFamily: 'Roboto',
primaryColor: Colors.deepOrangeAccent,
accentColor: Colors.purple,
textTheme: TextTheme(
headline: TextStyle(fontWeight: FontWeight.w500, color: Colors.blue),
title: TextStyle(fontSize: 50),
caption: TextStyle(
fontWeight: FontWeight.w400, fontSize: 14.0, color: Colors.green),
body1: TextStyle(fontSize: 20, color: Colors.purple),
));
}
In particolare, del metodo appena definito è interessate notare il textTheme
, che ha come valore un nuovo widget di tipo TextTheme
, il quale offre allo sviluppatore la possibilità di definire diversi stili tipografici, come ad esempio headline
, title
, body1
, caption
e molti altri ancora. Si raccomanda di consultare la documentazione relativa a questa classe per conoscere tutte le possibili proprietà e i valori raccomandati.
Per ogni proprietà usata di TextThema
abbiamo definito uno specifico TextStyle
(di cui abbiamo discusso nella lezione 14) definendo dimensione e colore.
Infine, come fontFamily
abbiamo utilizzato Roboto a titolo d’esempio, in quanto è l’unica famiglia di font fornita da Flutter di default. Qualora volessimo usare un font diverso dovremmo importarlo come abbiamo già visto nella lezione 14.
Impostiamo quindi il metodo appena creato come valore della proprietà theme ed eseguiamo l’applicazione.
Il risultato è decisamente interessante in quanto, con poche righe di codice, siamo riusciti a modificare i colori dei widget e la dimensione dei testi senza intervenire esplicitamente su questi.
Se per questo tema volessimo modificare la proprietà primarySwatch
, basterà aggiungere al codice definito le seguenti definizioni.
ThemeData _myCustomThemeDataDark() {
return ThemeData(
// . . .
primarySwatch: Colors.amber,
brightness: Brightness.dark,
));
}
Immaginiamo invece di voler definire uno stile per tutti i bottoni della nostra applicazione ma, invece di farlo manualmente, utilizziamo il buttonTheme
offerto da ThemeData
. Vediamo un esempio.
ThemeData _themeOverridingdefault() {
final ThemeData base = ThemeData.light();
return base.copyWith(
buttonTheme: base.buttonTheme.copyWith(
buttonColor: Colors.blueGrey,
shape: StadiumBorder(),
textTheme: ButtonTextTheme.primary,
splashColor: Colors.red,
)
);
}
A differenza del caso precedente, abbiamo creato un nuovo tema a partire dal tema light()
fornito da ThemeData
e abbiamo sovrascritto tramite il metodo copyWith()
la proprietà buttonTheme
, che a sua volta è una copia del buttonTheme
definito dal tema light
e di cui abbiamo modificato alcuni aspetti.
Questo approccio è molto utile nel momento in cui vogliamo modificare solo un aspetto di un tema definito in precedenza.
A questo punto, basterà aggiungere alla nostra schermata un RaisedButton
per poter vedere gli effetti della nostra modifica. Riportiamo di seguito solo la porzione di codice nuova da integrare nel codice pre-esistente.
@override
Widget build(BuildContext context) {
return Scaffold(
// . . .
children: <Widget>[
// . . .
Divider(),
RaisedButton(
child: Text("my Button theme"),
onPressed: () {},
)
],
),
),
// . . .
}
Aggiorniamo quindi il tema della nostra applicazione per vedere il risultato delle modifiche effettuate.
Come possiamo vedere, sebbene non abbiamo modificato lo stile del RaisedButton
, quest’ultimo ha una forma ovoidale determinata dallo StadiumBorder
e al tocco del bottone diventerà rosso. Tutto ciò grazie alla definizione del tema, che semplifica l’utilizzo dei widget di default forniti dal framework.
L’utilizzo dei temi globali è fondamentale quando vogliamo personalizzare col minimo sforzo i widget di base forniti dal framework, ma nel caso di custom widget creati da noi, il framework non sa quali colori associare o che stile tipografico applicare al testo.
Per poter applicare un particolare stile tipografico o un colore definito nel nostro tema a un nuovo widget, o a un qualsiasi altro widget di base della nostra applicazione, dobbiamo utilizzare il metodo Theme.of()
che, dato il contesto corrente, permette di accedere a tutte le proprietà di ThemeData
.
Ad esempio, utilizziamo il primo tema definito in questa lezione contenente la personalizzazione del textTheme
e modifichiamo tutti i componenti testuali della nostra applicazione mediante l’utilizzo del metodo Theme.of()
come nel seguente esempio.
@override
Widget build(BuildContext context) {
return Scaffold(
// . . .
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
child: Text('my custom theme',
style: Theme.of(context).textTheme.headline)),
Divider(),
Text(
'You have pushed the button this many times:',
style: Theme.of(context).textTheme.body1,
),
Text(
'$_counter',
style: Theme.of(context).textTheme.caption,
),
],
),
),
// . . .
}
In questo caso, per ogni componente testuale della nostra schermata abbiamo definito uno stile tra quelli presenti nel nostro textTheme
.
Eseguiamo quindi l’applicazione per vedere gli effetti della nostra modifica.
Il risultato ottenuto evidenzia come sia semplice riutilizzare i temi definiti per la nostra applicazione e quanto sia importante definire un tema per le nostre app al fine di:
- ridurre il codice ripetuto per lo stile di colori e testi;
- uniformare lo stile in tutte le sezioni dell’app.
Il codice di questa lezione è disponibile su GitHub.