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

Gestione dei Dialog

Un Dialog permette ad un'app di comunicare all'utente informazioni utili mediante una finestra modale interattiva: impariamo ad implementarlo su Flutter.
Un Dialog permette ad un'app di comunicare all'utente informazioni utili mediante una finestra modale interattiva: impariamo ad implementarlo su Flutter.
Link copiato negli appunti

Un altro componente che spesso torna utile durante lo sviluppo di un'applicazione è il dialog. Questo elemento ci permette di comunicare all'utente delle informazioni utili circa un task, e può contenere informazioni critiche, richiedere delle decisioni da parte dell'utente e coinvolgere più attività. Pertanto è conveniente utilizzarlo nel caso in cui si debba:

  • segnalare all'utente un errore che interrompe il normale flusso dell'applicazione;
  • mostrare all'utente delle informazioni che richiedono una sua azione, come anticipato all'inizio.

Come spesso ci è capitato di vedere in un'applicazione, i dialog sono un tipo di finestra modale che appare davanti al contenuto corrente, disabilitando tutte le funzionalità dell'applicazione e restando sullo schermo finché l'utente non ci interagisce.

Esistono diverse tipologie di dialog:

Tipo Descrizione
Alert dialog interrompe le azioni dell'utente mostrando informazioni importanti, dettagli o azioni da compiere in relazione al contesto nel quale si trova
Simple dialog mostra un lista di elementi alcuni dei quali potrebbero essere selezionabili dall'utente o mostra semplicemente un messaggio informativo
Confirmation dialog richiede all'utente di confermare una scelta
Full-screen dialog rispetto agli altri tipi di dialog, questo riempie completamente la schermata richiedendo all'utente di compiere una serie di operazioni, ad esempio la compilazione di una form

Flutter mette a disposizione due tipologie di widget, SimpleDialog ed AlertDialog, che vedremo nel corso di questa lezione. Entrambe le classi estendono la classe Dialog, da cui ereditano un insieme di proprietà, e definiscono dei comportamenti specifici offerti dalle linee guida del material design.

Le classi SimpleDialog ed AlertDialog

Familiarizziamo quindi con queste due classi analizzando le principali proprietà che impiegheremo in questa lezione. Per le altre proprietà non trattate o per ulteriori informazioni su questi componenti, si rimanda alla documentazione ufficiale dei Dialog.

Partiamo dal SimpleDialog.

Proprietà Tipo Accettato Descrizione
backgroundColor Color definisce il colore di sfondo del dialog
children List<Widget> rappresenta una lista di widget da visualizzare all'interno del dialog
contentPadding EdgeInsetsGeometry è il padding intorno al contenuto del dialog
elevation double rappresenta il livello di elevazione scelto per il dialog. Di default il valore è impostato a 24 e non può essere negativo
shape ShapeBorder la forma che si vuole dare al dialog
title Widget permette la definizione di un Widget che rappresenterà il titolo del dialog e la sua definizione è fondamentale, pur essendo opzionale, per far capire all'utente il contesto in cui si trova
titlePadding EdgeInsetsGeometry è il padding intorno al titolo del dialog

Molte delle proprietà appena definite per il SimpleDialog sono valide anche per l'AlertDialog (fatta eccezione per la proprietà children), che in più definisce le seguenti proprietà.

Proprietà Tipo Accettato Descrizione
action List<Widget> definisce un insieme di azioni che l'utente può compiere. Queste verranno mostrate sulla parte inferiore del dialog
content Widget rappresenta il contenuto che il dialog mostra nella porzione centrale del dialog. Tipicamente viene utilizzata una SingleChildScrollView per visualizzare un insieme di task che l'utente può compiere. In alternativa è possibile utilizzare un semplice Text widget
contentTextStyle TextStyle permette di definire uno stile personalizzato per il content

Esempi pratici

Entriamo nel vivo della lezione con alcuni esempi utili per gestire e personalizzare un SimpleDialog e un AlertDialog.

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à body, che andremo a impostare di volta in volta con la definizione di un nuovo esempio di SimpleDialog o di AlertDialog.

class MySimpleDialog extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Lesson 22'),
      ),
      body: /* set your Dialog*/,
    );
  }

Fatto ciò, partiamo da un esempio semplice ma efficace di SimpleDialog. In questo caso andiamo a creare un nuovo metodo che ritorna un SimpleDialog con un titolo e un testo.

Widget _mySimpleDialog() {
    return SimpleDialog(
      title: Text("Title of the Dialog"),
      children: [Text("This is the text of the Dialog")],
    );
  }

Come si può notare, il SimpleDialog definisce una lista di widget figli, che in questo caso abbiamo popolato come una lista composta da un Text widget. Associando come di consueto il metodo alla proprietà body del nostro widget MySimpleDialog, otterremo il risultato in figura.

Figura 147. Esempio di una SimpleDialog basilare per a) Android b) iOS

Esempio di una SimpleDialog basilare per a) Android b) iOS

Con poche righe di codice abbiamo raggiunto il nostro scopo e mostrato (staticamente) un dialog all'utente con un titolo e un testo scritto. Messaggio che giunge efficacemente, ma che risulta essere leggermente scarno dal punto di vista estetico.

Concentriamoci pertanto su come possiamo personalizzare questo componente utilizzando di volta in volta le proprietà appena discusse.

Ad esempio, immaginiamo di voler aggiungere del padding sia al titolo che ai widget definiti all'interno della proprietà children. Per farlo, definiamo le proprietà titlePadding e contentPadding sia verticalmente che orizzontalmente, come di seguito.

Widget _mySimpleDialogWithPadding() {
    return SimpleDialog(
      title: Text("Title of the Dialog"),
      titlePadding: EdgeInsets.symmetric(horizontal: 40, vertical: 50),
      contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
      children: [
        Text(
          "This is the text of the Dialog",
          style: TextStyle(fontSize: 20),
        ),
        Text(
          "This is a second line",
          style: TextStyle(fontSize: 14),
        ),
      ],
    );
  }

Eseguiamo quindi l'app per vedere le modifiche.

Figura 148. Utilizzo delle proprietà titlePadding e contentPadding per a) Android b) iOS

Utilizzo delle proprietà titlePadding e contentPadding per a) Android b) iOS

Rispetto al precedente SimpleDialog si può notare la spaziatura rispetto al bordo sinistro e tra il titolo e i widget.

Invece, se vogliamo modificarne la forma basterà utilizzare la proprietà shape e definire il tipo di forma che vogliamo dare al SimpleDialog. Vediamo come.

Widget _mySimpleDialogWithCustomShape() {
return SimpleDialog(
title: Text(
"Title",
textAlign: TextAlign.center,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
children: [
Text(
  "This is the text of the Dialog",
  style: TextStyle(fontSize: 15),
  textAlign: TextAlign.center,
)
],
);
}

In questo caso abbiamo deciso di arrotondare gli angoli del nostro SimpleDialog, rendendo la sua forma più gradevole e molto vicina ad una Card da mostrare all'utente. Inoltre, abbiamo centrato sia il titolo che il testo del messaggio contenuto in children, come si può notare dalla figura.

Figura 149. Utilizzo delle proprietà shape per a) Android b) iOS

Utilizzo delle proprietà shape per a) Android b) iOS

Come rimarcato più volte in questa guida, è essenziale personalizzare i widget per allinearli con lo stile della nostra applicazione. Anche i SimpleDialog non fanno eccezione. Supponiamo quindi di voler creare un dialog che abbia:

  • un titolo con un'icona;
  • un testo;
  • un'icona dopo il testo separata da una linea;
  • i bordi arrotondati;
  • un colore di sfondo;
  • un'elevazione di 10.

Un insieme di caratteristiche che potrebbe risultare articolato ma che richiede il minimo sforzo per essere definito se lavoriamo con le proprietà viste finora e con quanto abbiamo appreso in queste lezioni. Vediamo come implementare il nostro SimpleDialog.

Widget _mySimpleDialogWithCustomDetails() {
return SimpleDialog(
title: Row(
children: <Widget>[
  Icon(Icons.notifications),
  Text(
    "Title",
  )
],
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
backgroundColor: Colors.amber,
elevation: 10,
children: [
Text(
  "This is the text of the Dialog",
  style: TextStyle(fontSize: 15),
  textAlign: TextAlign.center,
),
Divider(
  thickness: 1,
),
Icon(Icons.home)
],
);
}
}

In questo esempio, per poter rappresentare il titolo affiancato da un'icona, abbiamo utilizzato il widget Row (di cui abbiamo parlato nella lezione 16) aggiungendo alla lista di widget prima l'icona e poi il testo. Per quanto riguarda la forma, il colore di sfondo e l'elevazione, abbiamo utilizzato le proprietà shape (vista prima), backgroundColor ed elevation, rispettivamente. Poi per l'icona finale separata da una linea dal testo del dialog, è bastato inserire nel punto giusto il widget Divider (visto nelle lezioni 18 e 19) come separatore di un lista di elementi.

Aggiornando la proprietà body ed eseguendo il codice otterremo il risultato in figura.

Figura 150. Personalizzazione di un SimpleDialog per a) Android b) iOS

Personalizzazione di un SimpleDialog per a) Android b) iOS

Ora che abbiamo compreso come personalizzare un SimpleDialog, vediamo come mostrarlo all'utente quando clicca ad esempio su un bottone, o meglio su un RaisedButton. Creiamo una nuova classe che chiameremo CustomDialogWithButton e che ci servirà per creare un nuovo RaisedButton. Di seguito lo scheletro della classe.

class CustomDialogWithButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
  // . . .
  }
}

Aggiungiamo a questa classe un nuovo metodo di tipo void che chiameremo customSimpleDialog. Questo metodo sarà responsabile di costruire un nuovo SimpleDialog, come uno di quelli visti in precedenza, e di mostrarlo all'utente finale tramite il metodo showDialog. Vediamo come.

void customSimpleDialog(BuildContext context) {
var dialog = SimpleDialog(
title: Row(
children: <Widget>[
  Icon(Icons.notifications),
  Text(
    "Title",
  )
],
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
backgroundColor: Colors.amber,
elevation: 10,
children: [
Text(
  "This is the text of the Dialog",
  style: TextStyle(fontSize: 15),
  textAlign: TextAlign.center,
),
Divider(
  thickness: 1,
),
Icon(Icons.home)
],
);
showDialog(
context: context,
builder: (BuildContext context) {
  return dialog;
});
}

In particolare, il metodo showDialog mostrerà il dialog al di sopra del contenuto corrente dell'applicazione. Questo metodo definisce inoltre una proprietà builder per la costruzione del Dialog che non condividerà lo stesso context da cui viene invocato il metodo showDialog.

Non resta che costruire il nostro RaisedButton.

Widget build(BuildContext context) {
return Center(
child: Container(
child: RaisedButton(
onPressed: () {
  customSimpleDialog(context);
},
child: Row(children: <Widget>[
  Icon(Icons.open_in_browser),
  Text(
    "Open Dialog",
    textAlign: TextAlign.center,
  )
]),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
width: 130,
));
}

Modifichiamo infine la proprietà home della classe MyApp come segue

home: Scaffold(
  appBar: AppBar(
    title: Text('Lesson 22'),
  ),
  body: CustomDialogWithButton(),
)

al fine di inizializzare la classe appena creata e avviamo l'applicazione per vedere il frutto del nostro lavoro.

Figura 151a. Esempio di SimpleDialog al click di un RaisedButton per Android

Esempio di SimpleDialog al click di un RaisedButton per Android

Figura 151b. Esempio di SimpleDialog al click di un RaisedButton per iOS

Esempio di SimpleDialog al click di un RaisedButton per iOS

Ora che abbiamo ben chiaro come utilizzare e personalizzare un SimpleDialog non ci resta che lavorare con gli AlertDialog. Questi widget, sebbene siano molto simili tra loro, hanno scopi ben diversi all'interno di un'applicazione, come anticipato all'inizio di questa lezione.

Creiamo un nuovo StatelessWidget in cui andare a definire di volta in volta il nostro AlertDialog tramite la proprietà body.

class MyAlertDialog extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Lesson 22'),
      ),
      body: /* set the AlertDialog here*/,
    );
  }
 // . . .
}

All'interno della stessa classe creiamo un nuovo metodo che chiameremo _myAlertDialog e che mostrerà un primo esempio di AlertDialog. In particolare il metodo si comporrà:

  • di due FlatButton (di cui abbiamo parlato nella lezione 15) che rappresenteranno le azioni che l'utente può compiere quando gli viene mostrato l'AlertDialog;
  • una variabile di tipo AlertDialog che definirà il nostro AlertDialog.

In particolare, il dialog sarà composto da un titolo, un contenuto testuale e due azioni ottenute dalla definizione dei FlatButton. Vediamo come tramite l'esempio seguente.

Widget _myAlertDialog(){
    Widget cancelButton = FlatButton(
      child: Text("Cancel"),
      onPressed:  () {
        print("Cancel");
      },
    );
    Widget okButton = FlatButton(
      child: Text("Ok"),
      onPressed:  () {
        print("Ok");
      },
    );
    AlertDialog basicAlertDialog = AlertDialog(
      title: Text("AlertDialog Title"),
      content: Text("Add a message here."),
      actions: [
        okButton,
        cancelButton,
      ],
    );
    return alertDialogWithMultipleButtons;
  }

Fatto ciò, eseguiamo la nostra applicazione ottenendo il risultato in figura.

Figura 152. Esempio di un AlertDialog con due azioni per a) Android b) iOS

Esempio di un AlertDialog con due azioni per a) Android b) iOS

Ovviamente, possiamo definire più di due azioni in quanto possiamo dare alla proprietà actions una lista di Widget. Quindi, all'interno dello stesso metodo possiamo aggiungere un terzo bottone del tipo

Widget thirdButton = FlatButton(
  child: Text("The Third option"),
  onPressed:  () {
    print("The Third option");
  },
);

e aggiungerlo alla lista di actions ottenendo il seguente risultato.

Figura 153. Esempio di un AlertDialog con tre azioni per a) Android b) iOS

Esempio di un AlertDialog con tre azioni per a) Android b) iOS

Ovviamente è fortemente sconsigliato definire più di due/tre azioni per un AlertDialog.

Personalizziamo adesso, il nostro AlertDialog modificandone forma, elevazione e colore.

AlertDialog customAlertDialog = AlertDialog(
  title: Text("AlertDialog Title"),
  content: Text("Add a message here."),
  actions: [
    okButton,
    cancelButton,
  ],
  shape: RoundedRectangleBorder(
      side: BorderSide(style: BorderStyle.none),
      borderRadius: BorderRadius.circular(10)
  ),
  elevation: 10,
  backgroundColor: Colors.amber,
);

Modifichiamo il valore di ritorno della funzione con il dialog appena creato ed eseguiamo l'applicazione.

Figura 154. Esempio di un AlertDialog personalizzato per a) Android b) iOS

Esempio di un AlertDialog personalizzato per a) Android b) iOS

Immaginiamo, infine, di voler mostrare un AlertDialog al tocco di un bottone, come fatto in precedenza per il SimpleDialog. All'interno della classe CustomDialogWithButton creiamo un nuovo metodo che chiameremo customAlertDialog, per creare un nuovo AlertDialog e mostrarlo all'utente sfruttando nuovamente la proprietà showDialog.

void customAlertDialog(BuildContext context){
    Widget cancelButton = FlatButton(
      child: Text("Cancel"),
      onPressed:  () {
        print("Cancel");
      },
    );
    Widget okButton = FlatButton(
        child: Text("Ok"),
        onPressed:  () {
          print("Ok");
        },
    );
    var dialog = AlertDialog(
      title: Text("AlertDialog Title"),
      content: Text("Add a message here."),
      actions: [
        okButton,
        cancelButton,
      ],
      shape: RoundedRectangleBorder(
          side: BorderSide(style: BorderStyle.none),
          borderRadius: BorderRadius.circular(10)
      ),
      elevation: 10,
      backgroundColor: Colors.amber,
    );
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return dialog;
        });
  }
}

Creato il nostro AlertDialog personalizzato non resta che aggiornare la proprietà onPressed del RaisedButton e modificare nuovamente la proprietà home della classe MyApp, esattamente come fatto in precedenza.

Eseguiamo, quindi, l'applicazione per vedere il risultato delle nostre modifiche.

Figura 155a. Esempio di AlertDialog al click di un RaisedButton per Android

Figura 155a. Esempio di AlertDialog al click di un RaisedButton per Android

Figura 155b. Esempio di AlertDialog al click di un RaisedButton per iOS

Figura 155b. Esempio di AlertDialog al click di un RaisedButton per iOS

Il codice di questa lezione è disponibile su GitHub.

Ti consigliamo anche