Flutter - Introdução aos Layouts
Como o conceito central do Flutter é Everything is widget , o Flutter incorpora uma funcionalidade de layout de interface de usuário nos próprios widgets. O Flutter fornece vários widgets especialmente projetados, como Container, Center, Align , etc., apenas com o propósito de definir a interface do usuário. Widgets construídos pela composição de outros widgets normalmente usam widgets de layout. Vamos aprender o conceito de layout Flutter neste capítulo.
Tipo de layout de widgets
Os widgets de layout podem ser agrupados em duas categorias distintas com base em seu filho -
- Widget apoiando uma única criança
- Widget que suporta vários filhos
Vamos aprender os dois tipos de widgets e sua funcionalidade nas próximas seções.
Widgets de filho único
Nesta categoria, os widgets terão apenas um widget como filho e cada widget terá uma funcionalidade de layout especial.
Por exemplo, o widget Center apenas centraliza o widget filho em relação ao widget pai e o widget Container fornece flexibilidade completa para colocá-lo filho em qualquer lugar dentro dele usando opções diferentes como preenchimento, decoração, etc.,
Widgets filho único são ótimas opções para criar widget de alta qualidade com funcionalidade única, como botão, rótulo, etc.
O código para criar um botão simples usando o widget Container é o seguinte -
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)
),
),
);
}
}
Aqui, usamos dois widgets - um widget de contêiner e um widget de texto . O resultado do widget é um botão personalizado, conforme mostrado abaixo -
Vamos verificar alguns dos widgets de layout filho único mais importantes fornecidos pelo Flutter -
Padding- Usado para organizar seu widget filho pelo preenchimento fornecido. Aqui, o preenchimento pode ser fornecido pela classe EdgeInsets .
Align- Alinhe seu widget filho dentro dele mesmo usando o valor da propriedade de alinhamento . O valor da propriedade de alinhamento pode ser fornecido pela classe FractionalOffset . A classe FractionalOffset especifica os deslocamentos em termos de uma distância do canto superior esquerdo.
Alguns dos valores possíveis de deslocamentos são os seguintes -
FractionalOffset (1.0, 0.0) representa o canto superior direito.
FractionalOffset (0,0, 1,0) representa a parte inferior esquerda.
Um exemplo de código sobre deslocamentos é mostrado abaixo -
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 - Ele dimensiona o widget filho e o posiciona de acordo com o ajuste especificado.
AspectRatio - Tenta dimensionar o widget filho para a proporção especificada
ConstrainedBox
Baseline
FractinallySizedBox
IntrinsicHeight
IntrinsicWidth
LiimitedBox
OffStage
OverflowBox
SizedBox
SizedOverflowBox
Transform
CustomSingleChildLayout
Nosso aplicativo hello world está usando widgets de layout baseados em material para projetar a página inicial. Vamos modificar nosso aplicativo hello world para construir a página inicial usando widgets de layout básicos, conforme especificado abaixo -
Container - Widget de contêiner genérico, filho único, baseado em caixa com alinhamento, preenchimento, borda e margem, juntamente com recursos de estilo ricos.
Center - Widget de contêiner filho simples e único, que centraliza seu widget filho.
O código modificado do widget MyHomePage e MyApp é como abaixo -
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,
),
)
);
}
}
Aqui,
O widget de contêiner é o widget de nível superior ou raiz. O contêiner é configurado usando a propriedade decoração e preenchimento para fazer o layout de seu conteúdo.
BoxDecoration tem muitas propriedades como cor, borda, etc., para decorar o widget do Container e aqui, a cor é usada para definir a cor do container.
o preenchimento do widget Container é definido usando a classe dgeInsets , que fornece a opção de especificar o valor de preenchimento.
Center é o widget filho do widget Container . Novamente, Text é filho do widget Center . Texto é usado para mostrar a mensagem e Centro é usado para centralizar a mensagem de texto em relação ao widget pai, Container .
O resultado final do código fornecido acima é um exemplo de layout, conforme mostrado abaixo -
Vários widgets filho
Nesta categoria, um determinado widget terá mais de um widget filho e o layout de cada widget é único.
Por exemplo, o widget de linha permite o layout de seus filhos na direção horizontal, enquanto o widget de coluna permite o layout de seus filhos na direção vertical. Ao compor Linha e Coluna , um widget com qualquer nível de complexidade pode ser construído.
Vamos aprender alguns dos widgets usados com frequência nesta seção.
Row - Permite organizar seus filhos de forma horizontal.
Column - Permite organizar seus filhos de forma vertical.
ListView - Permite organizar seus filhos como lista.
GridView - Permite organizar seus filhos como galeria.
Expanded - Usado para fazer com que os filhos do widget Linha e Coluna ocupem o máximo de área possível.
Table - Widget baseado em tabela.
Flow - Widget baseado em fluxo.
Stack - Widget baseado em pilha.
Aplicativo de layout avançado
Nesta seção, vamos aprender como criar uma interface de usuário complexa de lista de produtos com design personalizado usando widgets de layout filho único e múltiplos.
Para isso, siga a seqüência abaixo -
Crie um novo aplicativo Flutter no Android Studio, product_layout_app .
Substitua o código main.dart pelo seguinte código -
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,
Criamos o widget MyHomePage estendendo StatelessWidget em vez do StatefulWidget padrão e removemos o código relevante.
Agora, crie um novo widget, ProductBox de acordo com o design especificado, conforme mostrado abaixo -
O código para o ProductBox é o seguinte.
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()),
],
)
)
)
]
)
)
);
}
}
Observe o seguinte no código -
ProductBox usou quatro argumentos conforme especificado abaixo -
nome - nome do produto
descrição - descrição do produto
preço - preço do produto
imagem - Imagem do produto
ProductBox usa sete widgets integrados conforme especificado abaixo -
- Container
- Expanded
- Row
- Column
- Card
- Text
- Image
ProductBox é projetado usando o widget mencionado acima. A disposição ou hierarquia do widget é especificada no diagrama mostrado abaixo -
Agora, coloque alguma imagem fictícia (veja abaixo) para informações do produto na pasta de ativos do aplicativo e configure a pasta de ativos no arquivo pubspec.yaml conforme mostrado abaixo -
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
Finalmente, use o widget ProductBox no widget MyHomePage conforme especificado abaixo -
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"
),
],
)
);
}
}
Aqui, usamos ProductBox como filhos do widget ListView .
O código completo (main.dart) do aplicativo de layout do produto (product_layout_app) é o seguinte -
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()
),
],
)
)
)
]
)
)
);
}
}
O resultado final do aplicativo é o seguinte -