Flutter - Trabalhando com abas (Tab bars)


Neste artigo veremos como trabalhar com guias/abas ou Tab bars em uma aplicação Flutter.

O Flutter é um SDK de aplicativo móvel do Google que ajuda a criar aplicativos móveis modernos para iOS e Android usando uma única (quase) base de código.

Se você não conhece o Flutter veja o meu artigo :  Flutter - Primeiros contatos e impressões

Apresentando Tab-bar

Trabalhar com guias é um padrão comum em aplicativos que seguem as diretrizes do Material Design. O Flutter inclui uma maneira conveniente de criar layouts de guias como parte da biblioteca do material.

Neste artigo vamos mostrar um exemplo prático com guias cumprindo as etapas a seguir :

Para que as guias funcionem, você precisa manter a guia selecionada e as seções de conteúdo em sincronia. Este é o trabalho do TabController.

Para criar um TabController manualmente ou automaticamente usamos o widget DefaultTabController.

O widget DefaultTabController é um widget herdado que é usado para compartilhar um TabController com um TabBar ou um TabBarView. Ele é usado quando o compartilhamento de um TabController criado explicitamente não é conveniente porque os widgets da barra de guias são criados por um widget pai sem estado ou por widgets pais diferentes.

Usar DefaultTabController é a opção mais simples, pois cria um TabController e o torna disponível para todos os widgets descendentes.

DefaultTabController(
  length: 3,
  child: 
);
Ao definir um DefaultTabController usamos os argumentos:
  1. length - para indicar o número de guias
  2. child - definimos um widget filho, geralmente um Scaffold;
  3. initialIndex - O indice inicial da guia selecionada;

Vejamos um exemplo prático.

Criando o projeto Flutter

No Visual Studio Code tecle CTRL+ SHIFT+P para abrir a paleta de comandos e a seguir selecione a opção : Fluter:New Project;

A seguir informe o nome do projeto : flutter_circleimage e tecle ENTER;

A seguir inclua o código abaixo no arquivo main.dart para criar o leiaute padrão usando os Widgets MaterialApp e Scaffold :

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text("AppBar com guias"))
      ),
    );
  }
}

Vamos definir o código envolvendo o widget Scaffold por um widget DefaultTabController com duas guias :

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
          length: 2,
          child: Scaffold(
          appBar: AppBar(
            title: Text("AppBar com guias"),
            bottom: TabBar(
              tabs: <Widget>[
                Text("Primeira Guia"),
                Text("Segunda Guia"),
              ],
             )
            )
        ),
      ),
    );
  }
}

Neste código envolvemos o Scaffold pelo DefaultTabController que agora envolve tudo dentro do MaterialApp.

Na propriedade bottom definimos um TabBar com duas guias onde usamos o widget Text.

Podemos também exibir ícones ao invés de texto:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
          length: 2,
          child: Scaffold(
          appBar: AppBar(
            title: Text("AppBar com guias"),
            bottom: TabBar(
            tabs: <Widget>[
               Tab(icon : Icon(Icons.android)),
               Tab(icon : Icon(Icons.cloud_download))
            ],
             )
            )
        ),
      ),
    );
  }
}

Agora definimos duas Tabs com um ícone cada uma.

As Tabs não teriam nenhum sentido, a menos que adicionemos algumas ações a ela. No entanto, percebemos que as ações relativas à seleção de uma guia se refletem no body do Scaffold. E este mapeamento é feito pelo DefaultTabController. No entanto, precisamos fornecer um widget no body chamado TabBarView, que pode levar vários widgets filhos.

Por padrão, a sequência de declaração do widget filho será mapeada automaticamente para as guias, ou seja, o primeiro widget será chamado para a primeira guia, o segundo widget será chamado para a segunda guia e assim por diante.

Dessa forma cada existe uma correspondência entre o conteúdo de cada TabBar e do TabBarView.

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
          length: 2,
          child: Scaffold(
          appBar: AppBar(
            title: Text("AppBar com guias"),
            bottom: TabBar(
              tabs: <Widget>[
               Tab(icon : Icon(Icons.android)),
               Tab(icon : Icon(Icons.cloud_download))
              ],
             )
            ),
            body: TabBarView(
              children: <Widget>[
                Text("Primeira guia selecionada"),
                Text("Segunda guia selecionada")
              ],
            ),
        ),
      ),
    );
  }
}

Para concluir, e mostrar a correspondência entre a TabBar e a TabBarView, vamos criar 3 guias com ícones e definir a navegação usando 3 Containeres com cor e texto para perceber o sincronismo do mapeamento:

import 'package:flutter/material.dart';
void main() {
  runApp(TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: [
                Tab(icon: Icon(Icons.directions_car)),
                Tab(icon: Icon(Icons.directions_transit)),
                Tab(icon: Icon(Icons.directions_bike)),
              ],
            ),
            title: Text('Tabs Demo'),
          ),
          body: TabBarView(
            children: [
                new Container(
              color: Colors.deepOrangeAccent,
              child: new Center(
                child: new Text(
                  "Primeira Guia",
                  style: TextStyle(),
                ),
              ),
            ),
            new Container(
              color: Colors.blueGrey,
              child: new Center(
                child: new Text(
                  "Segunda guia",
                  style: TextStyle(),
                ),
              ),
            ),
            new Container(
              color: Colors.teal,
              child: new Center(
                child: new Text(
                  "Terceira guia",
                  style: TextStyle(),
                ),
              ),
            ), 
           ],
          ),
        ),
      ),
    );
  }
}

Pegue o projeto dos arquivos aqui: main_tabbar.dart

"Louvai ao SENHOR, porque ele é bom; porque a sua benignidade dura para sempre.
Louvai ao Deus dos deuses; porque a sua benignidade dura para sempre.
Louvai ao Senhor dos senhores; porque a sua benignidade dura para sempre."
Salmos 136:1-3

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti