Flutter - Introduzione ai layout
Poiché il concetto centrale di Flutter è Tutto è widget , Flutter incorpora una funzionalità di layout dell'interfaccia utente nei widget stessi. Flutter fornisce molti widget appositamente progettati come Contenitore, Centro, Allinea , ecc., Solo allo scopo di disporre l'interfaccia utente. I widget creati componendo altri widget normalmente utilizzano widget di layout. Apprendi il concetto di layout Flutter in questo capitolo.
Tipo di widget di layout
I widget di layout possono essere raggruppati in due categorie distinte in base al suo figlio:
- Widget che supporta un singolo bambino
- Widget che supporta più bambini
Impariamo sia il tipo di widget che la sua funzionalità nelle prossime sezioni.
Widget figlio singolo
In questa categoria, i widget avranno un solo widget come figlio e ogni widget avrà una funzionalità di layout speciale.
Ad esempio, il widget Centro centra il widget figlio rispetto al suo widget genitore e il widget Contenitore offre la flessibilità completa per posizionarlo in qualsiasi punto al suo interno utilizzando opzioni diverse come imbottitura, decorazione, ecc.,
I widget figlio singolo sono ottime opzioni per creare widget di alta qualità con funzionalità singole come pulsante, etichetta, ecc.
Il codice per creare un semplice pulsante utilizzando il widget Contenitore è il seguente:
class MyButton extends StatelessWidget {
MyButton({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
),
),
child: Container(
padding: const
EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
),
color: Colors.grey,
),
child: const Text(
'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
),
),
);
}
}
Qui abbiamo utilizzato due widget: un widget Contenitore e un widget Testo . Il risultato del widget è come un pulsante personalizzato come mostrato di seguito:
Controlliamo alcuni dei più importanti widget di layout per figlio singolo forniti da Flutter -
Padding- Usato per organizzare il suo widget figlio in base al riempimento specificato. Qui, il riempimento può essere fornito dalla classe EdgeInsets .
Align- Allinea il suo widget figlio al suo interno usando il valore della proprietà di allineamento . Il valore per la proprietà di allineamento può essere fornito dalla classe FractionalOffset . La classe FractionalOffset specifica gli offset in termini di distanza dall'angolo superiore sinistro.
Alcuni dei possibili valori di offset sono i seguenti:
FractionalOffset (1.0, 0.0) rappresenta l'angolo in alto a destra.
FractionalOffset (0.0, 1.0) rappresenta l'angolo inferiore sinistro.
Di seguito è riportato un codice di esempio sugli offset:
Center(
child: Container(
height: 100.0,
width: 100.0,
color: Colors.yellow, child: Align(
alignment: FractionalOffset(0.2, 0.6),
child: Container( height: 40.0, width:
40.0, color: Colors.red,
),
),
),
)
FittedBox - Ridimensiona il widget figlio e quindi lo posiziona in base all'adattamento specificato.
AspectRatio - Tenta di ridimensionare il widget figlio in base alle proporzioni specificate
ConstrainedBox
Baseline
FractinallySizedBox
IntrinsicHeight
IntrinsicWidth
LiimitedBox
OffStage
OverflowBox
SizedBox
SizedOverflowBox
Transform
CustomSingleChildLayout
La nostra applicazione Hello World utilizza widget di layout basati sui materiali per progettare la home page. Modifichiamo la nostra applicazione Hello World per creare la home page utilizzando i widget di layout di base come specificato di seguito -
Container - Widget contenitore generico, singolo figlio, basato su scatola con allineamento, riempimento, bordo e margine insieme a ricche caratteristiche di stile.
Center - Semplice, widget contenitore singolo figlio, che centra il suo widget figlio.
Il codice modificato del widget MyHomePage e MyApp è il seguente:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MyHomePage(title: "Hello World demo app");
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white,),
padding: EdgeInsets.all(25), child: Center(
child:Text(
'Hello World', style: TextStyle(
color: Colors.black, letterSpacing: 0.5, fontSize: 20,
),
textDirection: TextDirection.ltr,
),
)
);
}
}
Qui,
Il widget contenitore è il widget di livello superiore o radice. Il contenitore viene configurato utilizzando la proprietà di decorazione e riempimento per il layout del contenuto.
BoxDecoration ha molte proprietà come colore, bordo, ecc., Per decorare il widget Contenitore e qui, il colore viene utilizzato per impostare il colore del contenitore.
il riempimento del widget Contenitore viene impostato utilizzando la classe dgeInsets , che fornisce l'opzione per specificare il valore di riempimento.
Center è il widget figlio del widget Contenitore . Di nuovo, Text è il figlio del widget Center . Il testo viene utilizzato per mostrare il messaggio e il Centro viene utilizzato per centrare il messaggio di testo rispetto al widget principale, Contenitore .
Il risultato finale del codice riportato sopra è un esempio di layout come mostrato di seguito:
Widget figlio multipli
In questa categoria, un dato widget avrà più di un widget figlio e il layout di ogni widget è unico.
Ad esempio, il widget Riga consente il layout dei suoi figli in direzione orizzontale, mentre il widget Colonna consente il layout dei suoi figli in direzione verticale. Componendo Riga e Colonna , è possibile creare widget con qualsiasi livello di complessità.
Impariamo alcuni dei widget usati di frequente in questa sezione.
Row - Permette di disporre i suoi figli in modo orizzontale.
Column - Permette di disporre i suoi figli in modo verticale.
ListView - Permette di organizzare i suoi figli come lista.
GridView - Permette di organizzare i suoi bambini come galleria.
Expanded - Utilizzato per fare in modo che i widget figlio di Riga e Colonna occupino la massima area possibile.
Table - Widget basato su tabella.
Flow - Widget basato sul flusso.
Stack - Widget basato su stack.
Applicazione di layout avanzato
In questa sezione, impariamo come creare un'interfaccia utente complessa di elenchi di prodotti con un design personalizzato utilizzando widget di layout figlio singoli e multipli.
A tal fine, seguire la sequenza indicata di seguito:
Crea una nuova applicazione Flutter in Android Studio, product_layout_app .
Sostituisci il codice main.dart con il codice seguente:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', theme: ThemeData(
primarySwatch: Colors.blue,),
home: MyHomePage(title: 'Product layout demo home page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(this.title),),
body: Center(child: Text( 'Hello World', )),
);
}
}
Here,
Abbiamo creato il widget MyHomePage estendendo StatelessWidget invece del predefinito StatefulWidget e quindi rimosso il codice pertinente.
Ora, crea un nuovo widget, ProductBox secondo il design specificato come mostrato di seguito -
Il codice per ProductBox è il seguente.
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image})
: super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2), height: 120, child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
Image.asset("assets/appimages/" +image), Expanded(
child: Container(
padding: EdgeInsets.all(5), child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.name, style: TextStyle(fontWeight:
FontWeight.bold)), Text(this.description),
Text("Price: " + this.price.toString()),
],
)
)
)
]
)
)
);
}
}
Si prega di osservare quanto segue nel codice:
ProductBox ha utilizzato quattro argomenti come specificato di seguito:
nome: nome del prodotto
descrizione: descrizione del prodotto
prezzo - Prezzo del prodotto
immagine - Immagine del prodotto
ProductBox utilizza sette widget incorporati come specificato di seguito -
- Container
- Expanded
- Row
- Column
- Card
- Text
- Image
ProductBox è progettato utilizzando il widget di cui sopra. La disposizione o la gerarchia del widget è specificata nel diagramma mostrato di seguito:
Ora, posiziona un'immagine fittizia (vedi sotto) per le informazioni sul prodotto nella cartella degli asset dell'applicazione e configura la cartella degli asset nel file pubspec.yaml come mostrato di seguito -
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
iPhone.png
Pixel.png
Laptop.png
Tablet.png
Pendrive.png
Floppy.png
Infine, usa il widget ProductBox nel widget MyHomePage come specificato di seguito -
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("Product Listing")),
body: ListView(
shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget> [
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"
),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"
),
],
)
);
}
}
Qui, abbiamo utilizzato ProductBox come elementi secondari del widget ListView .
Il codice completo (main.dart) dell'applicazione di layout del prodotto (product_layout_app) è il seguente:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Product layout demo home page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"
),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"
),
],
)
);
}
}
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image}) :
super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 120,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
this.name, style: TextStyle(
fontWeight: FontWeight.bold
)
),
Text(this.description), Text(
"Price: " + this.price.toString()
),
],
)
)
)
]
)
)
);
}
}
L'output finale dell'applicazione è il seguente: