Objeto: criação de um aplicativo simples, com uma tela e padrão de cores, utilizando construtores, composição e parâmetros nomeados.
Principais termos técnicos abordados: classes, objetos, construtores, named parameters, widget, flutter
Requisitos para as instruções funcionarem: navegador ou ide (VS Code, Android Studio etc.)
Requisitos para compreensão das instruções: noções básicas de programação
Como ler essa receita: instruções, dentro dos passos da receita e que requerem ação sua no computador, estarão escritas em cor azul. Comentários sobre os passos estarão em fonte normal, cor preta. Comandos, código-fonte, termos técnicos ou configuração explícita, estarão com fonte diferenciada.
Observação: eventuais instruções de terminal serão comandos Linux. Adapte caso esteja usando outro sistema operacional
Nesta receita vamos montar a interface de um aplicativo simples em flutter e exibi-la. Flutter é um framework para interfaces gráficas na linguagem dart. Você não precisa entender exatamente o que é um framework agora, considere apenas que seja uma biblioteca mais espertinha. Por ser uma biblioteca, ela oferece diversos componentes gráficos - botões, painéis, campos de formulário etc. - já prontinhos para você usar e compor sua interface com o usuário. Por ser mais espertinha, sabe como renderizar e atualizar as interfaces que você montou com os componentes.
Cada componente gráfico desses disponibilizados no flutter é uma classe a que chamamos, genericamente, de Widget. Um botão? é um Widget. Um menu? É um Widget. Uma animação? É um Widget. Você vai ter muita dificuldade em achar algo que não seja um Widget. Quase tudo é um Widget.
Mas um Widget não deixa de ser uma classe, com propriedades e atributos. E, claro, CONSTRUTORES. Assim, sabendo o que componentes gráficos os Widgets representam E como chamar seus construtores podemos construir nossas telas.
Portanto, vamos fazer tudo com componentes que outros programadores implementaram para nós. Precisamos atentar, basicamente, para que Widgets usar e para os parâmetros que seus construtores requerem - será mais um exercício de saber construir e interconectar objetos e de obter alguma familiaridade com os componentes gráficos. Para emoções maiores, precisaremos de mais algumas receitas.
Abrir o site https://dartpad.dev (ou o zapp.run).
ou alguma IDE de sua preferência, como o VS Code ou o Android Studio
Precisamos de um objeto que represente a tela inicial do nosso aplicativo. Um widget que pode desempenhar esse papel é o MaterialApp.
Escreva o seguinte código no editor:
import 'package:flutter/material.dart';
void main() {
MaterialApp app = MaterialApp();
runApp(app);
}
Bem, temos um programa principal, a função main, que é o que vai ser executado quando a gente empurrar o clique em algum botão Run ou coisa parecida.
No main estamos criando um objeto do widged MaterialApp, que é nossa tela principal. Só vai ter uma, aliás, então é nossa única tela.
Esse objeto app é nossa tela e estamos passando esse objeto para o método runApp para que a tela seja exibida.
- Mas e aquele import, professor?
Bem, você não escreveu nenhuma classe MaterialApp, escreveu? Então o cara legal que escreveu pôs lá nesse arquivo material.dart e estamos importando a classe de lá. É mais fácil que escrever a classe, acredite ;)
Mas não rode nada ainda. A coisa não pode ser tão simples assim.
Precisamos por alguma coisa nesse MaterialApp. O construtor aceita dois parâmetros nomeados. Aceita uma ruma, na verdade, mas vamos utilizar o theme e o home. O theme deve ser um objeto da classe ThemeData, cujo construtor também tem seus próprios parâmetros. E o home pode ser um objeto Text. Pode ser um objeto de outras classes também, mas vamos começar devagar.
Edite o código e deixo-o como a seguir:
void main() {
MaterialApp app = MaterialApp(
theme: ThemeData(
primarySwatch: Colors.purple,
),
home: Text("Apenas começando..."));
runApp(app);
}
Bem, agora dá pra rodar nosso primeiro aplicativozinho. Você deve ver algo assim.
Claro que ainda não é exatamente um aplicativo para sua mãe ficar orgulhosa de você, mas temos algumas coisas a analisar que são importantes.
Apareceu um theme: e um home: dentro do construtor de MaterialApp. Esses são os chamados parâmetros nomeados ou named parameters - parâmetros que precisamos passar acompanhados de seus nomes e não em ordem pré-estabelecida como estamos acostumados em outras linguagens.
Vamos entender esse objeto MaterialApp como uma caixa onde a gente pode botar uma ruma de coisa dentro, e a gente pode fazer isso através do construtor. Uma coisa que a gente pode por é identificada por theme, a outra é identificada por home. Na coisa identificada por theme a gente pode por um outro objeto - uma outra caixa, um ThemeData. E, dentro desta outra caixa podemos colocar algo identificado por primarySwatch. Esse parâmetro indica a gama de cores que será utilizada por default nos diversos componentes gráficos que podem compor seu aplicativo. Estamos atribuindo a constante Colors.purple.
Finalmente, escrevemos home: Text("Apenas começando...") para por um componente gráfico de texto como conteúdo principal do MaterialApp. Não é o ideal, claro. Mas é um começo.
Note que o construtor de Text não requer o tal named parameter. Basta passar um String que o construtor saberá o que ele representa. Esse é o positional parameter, bem mais conhecido em outras linguagens de programação como Java ou C.
É melhor você se acostumar com os named parameters.
Modifique o código para criarmos um objeto da classe Scaffold, que tem mais cara de tela de aplicativo do que um simples objeto Text.
import 'package:flutter/material.dart';
void main() {
MaterialApp app = MaterialApp(
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: Scaffold(
appBar: AppBar(title: Text("Meu app")),
body: Text("Apenas começando..."),
bottomNavigationBar: Text("Botão 1"),
));
runApp(app);
}
Rode o programa e analise os impactos na interface gráfica.
Você ainda não vai pegar ninguém por causa disso, mas a evolução é nítida.
Já temos diversos outros componentes, mas a criação se dá, basicamente, do mesmo jeito. Chamando construtores, passando named parameters, botando uma caixa dentro da outra até termos o que a gente quer. Eu já pedi para você entender esses objetos como caixas, então eu peço, agora, para que você entenda os construtores como fábricas de caixas. Chame uma criança dessas (um construtor), e ganhe uma caixa prontinha. E com o que você quiser por dentro dela, já que passamos parâmetros para essas fábricas.
Assim, lá no nosso home, do MaterialApp em vez de colocarmos uma caixa Text, em que, basicamente, só cabe um texto besta, colocamos uma caixa mais adequada, uma caixa Scaffold:
(...)
home: Scaffold(
appBar: AppBar(title: Text("Meu app")),
body: Text("Apenas começando..."),
bottomNavigationBar: Text("Botão 1"),
)
(...)
A fábrica de Scaffold permite que você ponha dentro das caixas que ela fabrica um appBar, um body, e um bottomNavigationBar. A gente não precisa ter uma menter brilhante para olhar para a interface gráfica da figura que você acabou de ver e identificar o que cada um desses parâmetros representam - o appBar é aquela barrinha cor púrpura na parte de cima, o bottomNavigationBar é aquela porção de baixo da tela e o body é tudo que tem no meio entre esses dois componentes gráficos. A gente pôs apenas um Text, mas podia ter posto o que bem entendesse.
Esses parâmetros nomeados representam também objetos gráficos. Na nossa analogia, cada uma dessas crianças, em si, é outra caixa, então você pode escolher entre diversos widgets e chamar a fábrica adequada para compor a interface como bem entender. Nesse exemplo, escolhemos uma caixa AppBar para o appBar (se ligue no a maiúsculo e minúsculo), uma caixa Text para o body e outra caixa Text para o bottomNavigationBar.
- Ah, professor, ficou fuleira demais esse texto "Apenas começando"... e se eu quisesse centralizá-lo?
Bem, a gente pode se divertir bastante com essa metáfora das caixas. O "Apenas começando" está dentro de uma caixa que sabe mostrar texto mas se enrola na hora de entralizar seu conteúdo do jeito que a gente necessita. Uma solução é fabricar uma caixa que sabe centralizar seu conteúdo e botar o Text("Apenas começando") dentro dessa caixa, assim a gente ajunta as duas funcionalidades que queremos, centralizar e exibir texto. Vamos fazer isso.
Edite seu código e deixe-o como a seguir:
void main() {
MaterialApp app = MaterialApp(
title: 'Primeiro App',
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: Scaffold(
appBar: AppBar(title: Text("Meu app")),
body: Center(
child: Text("Apenas começando...")
),
bottomNavigationBar: Text("Botão 1"),
));
runApp(app);
}
A única coisa que mudou em relação ao código anterior foi a fábrica Center, em negrito, e com isso obtivemos a mágica que estávamos buscando...
Podemos fazer mais coisas também. No body, dentro do Center, podemos botar diversos componentes gráficos em vez de um só, um abaixo do outro. Para isso precisamos da mesma coisa que precisamos pra tudo nessa receita: saber um widget que contemple essa funcionalidade e saber chamar sua fábrica. Esse Widget é o Column, o nome meio que diz tudo. Sua fábrica aceita um parâmetro, children, o que meio que também diz tudo mas vai requerer algum comentário mais adiante.
Modifique seu código...
import 'package:flutter/material.dart';
void main() {
MaterialApp app = MaterialApp(
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: Scaffold(
appBar: AppBar(title: Text("Meu app")),
body: Center(
child: Column(
children: [
Text("Apenas começando..."),
Text("No meio..."),
Text("Terminando...")
]
)
),
bottomNavigationBar: Text("Botão 1"),
));
runApp(app);
}
A interface resultante é algo assim...
Note que children é plural - criançaS ou filhoS, em inglês. Assim, esse parâmetro de Column requer uma coleção (vetor, array, lista- chame como quiser) de caixas, e indicamos isso pelo uso dos colchetes em vermelho lá no código. Há vários widgets que recebem parâmetros de nome children. Todos eles, rigorosamente, indicam o uso de coleções.
- Ah, professor, mas perdemos o alinhamento centralizado vertical com essa nova versão.
Perdemos sim. Certamente se resolve esse tipo de problema ou ajustando algum parâmetro nas caixas existentes ou colocando tudo isso numa nova caixa que faça o que a gente quer. Mas a gente tem outras coisas legais pra fazer também, vamos aos exercícios.
Modifique os valores do primarySwatch e veja os efeitos na interface.
Modifique algum texto do body, tente estilizá-lo, mudar a fonte ou botar em negrito. Como fazer? Pesquise flutter styled text.
Há um widget complementar ao Column, que é o Row, que serve para alinhar uma coleção de widgets um ao lado do outro e não um abaixo do outro. Use esse widget e ponha três Text no bottomNavigationBar.
Em vez de Text na barra de navegação inferior, use botões de verdade, é de se esperar que haja fábricas para isso. Pesquise por flutter ElevatedButton example e desenrole.
Faça com que um dos botões seja um botão de ícone. Pesquise por flutter IconButton example e seja feliz.
Faça com que os botões fiquem centralizados. Você pode precisar de widgets Expanded para isso. Pode haver outras soluções sem Expanded também.
Há muitas e muitas outras coisas que podemos botar nas caixas ThemeData. Que tal dar uma olhada e modificar seu programa para que a fonte default dos componentes de texto seja uma fonte escolhida por você.
Aquela coleção children no widget Column não precisa ser uma coleção apenas de Text. A coleção pode ter dentro dela quaisquer widgets e pode ter widgets de fábricas diferentes dentro dela! Pode ter um texto, dois botões e uma imagem, por exemplo. Assim, acrescente àqueles 3 Text uma imagem da internet. É muito simples. Se você mexer em muita coisa, provavelmente está errado. Lembre que a imagem deve ser carregada da internet (via URL) e não do disco rígido. Não vou dar dica de pesquisa dessa vez, veja como você se sai por si próprio.
É muito chato para o usuário ficar esperando sem ver nada enquanto uma imagem é carregada da internet. Exiba alguma imagem alternativa enquanto o carregamento estiver acontecendo e faça um efeito de fade in quando a imagem finalmente for carregada. Sem dicas de pesquisa.
Faça um novo aplicativo. Pode copiar e colar o app dessa receita para começar. Substitua title do AppBar por um texto com o string "Cervejas". Em seguida, substitua o body do Scaffold por uma tabela, essa tabela pode ser construída através do widget DataTable. Os cabeçalhos das colunas da tabela devem ter os rótulos "Nome", "Estilo" e "IBU". Preencha a tabela com 3 linhas. A linha 1 deve ter os valores La Fin Du Monde, Bock e 65. A linha 2 deve ter os valores Sapporo Premium, Sour Ale e 54. E a linha 3 deve ter os valores Duvel, Pilsner e 82.
Tente acrescentar diversas outras linhas (invente os dados). O que acontece quando as informações não cabem mais na tela? Que tal fazer com que se possa deslizar pelos dados da tabela através do mouse ou de gesto com o dedo? É bem mais fácil do que parece e tem tudo a vem com a moral dessa receita. Ache uma caixa que saiba implementar essa funcionalidade (isso se chama scroll) e fabrique essa caixa colocando seu DataTable dentro dela. E só.
Faça um novo aplicativo. A ideia é a mesma da questão 10, apresentar dados em componentes gráficos diferentes. Sendo que eu vou te dar menos ajuda, dessa vez. Na verdade, vou apenas mostrar o app funcionando. Tente pesquisar na internet e desenrolar sozinho. A solução é mais simples do que a da questão 10.