Layout master-detail in Flutter
Quello che vogliamo creare è un classico layout master-detail in Flutter, senza l'ausilio di qualche sorta di designer (sempre se ne esistono).
Cominciamo col creare una nostra classe "POJO":
import 'package:meta/meta.dart';
class Nota {
Nota({
@required this.id,
@required this.titolo,
@required this.testo,
});
final int id;
final String titolo;
final String testo;
}
final List<Nota> note = <Nota>[
Nota(id: 1, titolo: "UNO", testo: "TESTO 1"),
Nota(id: 2, titolo: "DUE", testo: "TESTO 2")
];
Qui creiamo anche una lista che useremo dopo.
Poi creiamo una ListView che le visualizzi tutte:
import 'package:mp_notes/nota.dart';
import 'package:flutter/material.dart';
class NotaList extends StatelessWidget {
NotaList({
@required this.notaSelectedCallback,
this.selectedNota,
});
final ValueChanged<Nota> notaSelectedCallback;
final Nota selectedNota;
@override
Widget build(BuildContext context) {
return ListView(
children: note.map((nota) {
return ListTile(
title: Text(nota.titolo),
onTap: () => notaSelectedCallback(nota),
selected: selectedNota == nota,
);
}).toList(),
);
}
}
Il passo successivo è creare una classe che visualizzi una nota singola:
import 'package:mp_notes/nota.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
class NotaDettagli extends StatelessWidget {
NotaDettagli({@required this.isTablet, @required this.nota});
final bool isTablet;
final Nota nota;
@override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
final Widget content = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
nota?.titolo ?? 'Nessun elemento selezionato',
style: textTheme.headline,
),
Text(
nota?.testo ?? '',
style: textTheme.subhead,
),
],
);
if (isTablet) {
return Center(child: content);
}
return Scaffold(
appBar: AppBar(
title: Text(nota.titolo),
),
body: Center(child: content),
);
}
}
A questo punto abbiamo costruito alcune parti del layout; adesso vediamo la parte più importante:
import 'package:mp_notes/nota.dart';
import 'package:mp_notes/nota_dettagli.dart';
import 'package:mp_notes/nota_list.dart';
import 'package:flutter/material.dart';
class MasterDetailLayout extends StatefulWidget {
@override
NotaMasterDetailLayoutState createState() => NotaMasterDetailLayoutState();
}
class NotaMasterDetailLayoutState extends State<MasterDetailLayout> {
static const int tabletBreakpoint = 600;
Nota selectedNota;
Widget mobileLayout() {
return NotaList(
notaSelectedCallback: (nota) {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return NotaDettagli(
isTablet: false,
nota: nota,
);
},
),
);
},
);
}
Widget tabletLayout() {
return Row(
children: <Widget>[
Flexible(
flex: 1,
child: Material(
elevation: 4.0,
child: NotaList(
notaSelectedCallback: (nota) {
setState(() {
selectedNota = nota;
});
},
selectedNota: selectedNota,
),
),
),
Flexible(
flex: 3,
child: NotaDettagli(
isTablet: true,
nota: selectedNota,
),
),
],
);
}
@override
Widget build(BuildContext context) {
Widget content;
var shortestSide = MediaQuery.of(context).size.shortestSide;
if (shortestSide < tabletBreakpoint) {
content = mobileLayout();
} else {
content = tabletLayout();
}
return Scaffold(
appBar: AppBar(
title: Text('MP Note'),
),
body: content,
);
}
}
Qui incapsuliamo i precedenti pezzi di layout, andando anche a vedere se siamo su un dispositivo tablet o meno (o almeno ci proviamo, vista la quantità di dispositivi diversi che troviamo oggi in giro).
Questo il file Dart che rappresenta l'entrypoint della app (main.dart):
import 'package:mp_notes/master_detail_layout.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MP Note',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: MasterDetailLayout(),
);
}
}
Enjoy!
dart flutter master-detail listview
Commentami!