Abbiamo già parlato di Flutter in un altro articolo del nostro blog, ma oggi vogliamo andare un po’ più nel dettaglio e sporcarci le mani con del codice!

In uno dei progetti che stiamo sviluppando si è palesata la necessità di realizzare dei widget responsive: l’applicazione (ad uso interno di una azienda) verrà infatti utilizzata sia su smartphone che su tablet. Le informazioni da mostrare nell’app sono numerose, ed è quindi necessario organizzare al meglio gli spazi.

Nelle prossime immagini potete vedere un esempio: su tablet l’elenco è mostrato sotto forma di tabella in quanto lo spazio non manca e possiamo organizzare i dati su varie colonne.

Su tablet, le informazioni sono mostrate sotto forma di tabella

Su smartphone le cose si fanno più complicate, ed al posto della tabella i dati sono organizzati sotto forma di ListTile: le colonne spariscono e le informazioni sono divise in un titolo ed un sottotitolo.

Su smartphone, le informazioni sono visualizzate sotto forma di ListTile

Era necessario implementare lo stesso comportamento anche in altre parti dell’app: abbiamo quindi creato un semplicissimo Widget che ci permettesse di rendere responsive le nostre interfacce.

Su tablet landscape, vengono visualizzati 6 blocchi per riga
Su tablet portrait, vengono visualizzati 4 blocchi per riga
Su smartphone, vengono visualizzati 2 blocchi per riga

Come abbiamo fatto?

Di base Flutter ci fornisce un oggetto MediaQuery che possiamo usare in qualsiasi momento per avere informazioni sull’aspetto corrente della viewport del dispositivo.

Abbiamo poi usato un approccio a “builder” come avviene in tanti altri widget di Flutter (ad esempio StreamBuilder) ed in pochissime righe di codice abbiamo realizzato il nostro widget responsive!

import 'package:flutter/material.dart';
import 'constants.dart';

typedef Widget BuildFunction(BuildContext context);

class ResponsiveBuilder extends StatelessWidget {
  final BuildFunction buildSm;
  final BuildFunction buildMd;
  final BuildFunction buildLg;

  ResponsiveBuilder({
    this.buildSm, 
    this.buildMd, 
    this.buildLg
  });

  @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;

    if(width < Constants.mediaMdWidth) {
      return buildSm(context);
    }
    if(width < Constants.mediaLgWidth) {
      return buildMd(context);
    }
    return buildLg(context);
  }
}

Come potete vedere il codice è molto semplice; come costanti per i breakpoint abbiamo usato 600 e 900, ma siete liberi di sperimentare con i valori che volete.

Ecco come viene poi utilizzato il nostro widget all’interno dell’app.

@override
Widget build(BuildContext context) => Scaffold(
  appBar: [...],
  drawer: [...],
  body: ResponsiveBuilder(
    buildSm: (BuildContext context) => _buildGrid(2),
    buildMd: (BuildContext context) => _buildGrid(4),
    buildLg: (BuildContext context) => _buildGrid(6),
  )
);

La funzione _buildGrid in questo esempio creerà una griglia (come quella che vediamo nelle immagini sopra) con N elementi per riga, dove N è il parametro che viene passato in input alla funzione (nel nostro caso 2 su smartphone, 4 su tablet portrait e 6 su tablet landscape).

Semplice no?

Ci piace molto lavorare con Flutter: giorno per giorno ci rendiamo sempre più conto che il suo approccio a Widget rende molto semplice la scrittura di codice riutilizzabile, non sono all’interno della stessa app, ma anche (anzi, soprattutto!) tra app diverse.