Blog Formação DEV

Navegação com Barra Inferior com Flutter

Neste artigo será mostrado passo a passo como criar uma navegação por meio de barra inferior para aplicativos feitos em Flutter.
Navegação com Barra Inferior com Flutter
Texto de: Lucas Galdino

Introdução

Atualmente as telas de celulares estão cada vez maiores e mais esticadas, abandonando a proporção 16:9 e utilizando variações próximas do 21:9, ou seja, as telas estão mais altas. Com isso, o acesso à parte superior da tela pode ficar um pouco complicado em momentos onde precisamos utilizar o celular com apenas uma das mãos, ou para pessoas com mãos menores. Nesses casos, a barra inferior de navegação acaba sendo indispensável para uma boa experiência de usuário e neste artigo veremos como implementá-la.

Criando o projeto

Começaremos a implementação criando um projeto com o comando abaixo.

flutter create navegando 

Após a criação do projeto vamos fazer o básico. Primeiro vou deletar a pasta "test" e vou editar o arquivo "main.dart" para deixar ele da seguinte maneira:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Navegação',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Navegação'),
      ),
    );
  }
} 

O resultado na tela ficará assim:

Implementando a Bottom Navigator Bar

Agora vamos definir a barra de navegação inferior. Nessa barra, definimos quantos botões teremos, e as propriedades desses ícones como texto e ícone. Esses botões são organizados na forma de array, e barra conta também com a propriedade "currentIndex" que indica qual dos botões está ativo no momento.

No meu caso, vou querer inicializar a propriedade "currentIndex" com o valor 0, o que significa que a página inicial será o primeiro elemento dos "items" que defini como sendo a página "Home". Agora basta inserir o código abaixo logo abaixo do "AppBar" do nosso "Scaffold" para de fato criar a barra de navegação.

appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Navegação'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: 0,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            label: "Home",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.add_a_photo_outlined),
            label: "Postar",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person_2_outlined),
            label: "Perfil",
          ),
        ],
      ), 

E o resultado será o seguinte:

Agora vou criar uma pasta chamada "telas" dentro da pasta "lib". Dentro dessa nova pasta vou criar um arquivo para cada tela que temos na barra de navegação criada logo acima. Ou seja, um arquivo "home.dart", um arquivo "postar.dart" e um arquivo "perfil.dart". A organização das pastas ficará assim:

Os arquivos vão conter códigos bem simplificados, apenas modificando a cor de fundo de cada tela para sabermos em qual tela estamos. Aqui o código para cada arquivo.

Arquivo "home.dart":

import 'package:flutter/material.dart';

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.red);
  }
} 

Arquivo "postar.dart":

import 'package:flutter/material.dart';

class Postar extends StatelessWidget {
  const Postar({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.green);
  }
} 

Arquivo "perfil.dart":

import 'package:flutter/material.dart';

class Perfil extends StatelessWidget {
  const Perfil({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.blue);
  }
} 

Voltando agora para o arquivo "main.dart", vamos criar uma lista com todas as nossas telas dentro do nosso widget principal. Para iniciar tudo, precisamos importar as três novas telas na parte mais acima do código.

import 'telas/home.dart';
import 'telas/postar.dart';
import 'telas/perfil.dart'; 

Com o import feito, podemos criar a lista de telas logo acima do "@override" do "Scaffold" principal. Dessa forma:

class _MyHomePageState extends State<MyHomePage> {
  final List<Widget> telas = [
    const Home(),
    const Postar(),
    const Perfil(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar( 

Agora podemos criar um "body" para o nosso "Scaffold" principal, fazendo com que ele aponte para nossas novas páginas. Inicialmente ele vai apontar para a primeira página da recém-criada lista de telas:

return Scaffold(
      appBar: AppBar(title: Text("Bottom Navigation")),
      body: _telas[0],
      bottomNavigationBar: BottomNavigationBar( 

Agora vou criar uma variável que vai armazenar o índice da tela atual na qual estamos navegando e também uma função que vai lidar com a mudança desse índice e por consequência, lidar com a mudança de telas. Basta adicionar o seguinte código logo acima da lista que criamos antes:

class _MyHomePageState extends State<MyHomePage> {
  int telaAtual = 0;

  void trocandoTela(int novaTela) {
    setState(() {
      telaAtual = novaTela;
    });
  }

  final List<Widget> telas = [
    const Home(),
    const Postar(),
    const Perfil(),
  ]; 

Agora, para finalizar, basta atualizar um pouco o widget “Scaffold”. Primeiro é necessário alterar o valor que está no “body” para apontar para a variável que indica a tela. Depois, alterar o "currentIndex" para mostrar a página conforme a variável que criamos para armazenar o índice da página. Por último, vamos adicionar a propriedade "onTap" dentro do widget "bottomNavigationBar" e dentro dela utilizar a referência para a função "trocandoTela", criando de fato o efeito de troca de telas no aplicativo. Após as mudanças o código do “Scaffold” ficará da seguinte forma:

return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Navegação'),
      ),
      body: telas[telaAtual],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: telaAtual,
        onTap: trocandoTela,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            label: "Home",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.add_a_photo_outlined),
            label: "Postar",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person_2_outlined),
            label: "Perfil",
          ),
        ],
      ),
    ); 

E o resultado será o esperado, sempre que trocarmos de página clicando nos botões da barra, a cor do fundo dela irá mudar!

Aqui o código final do arquivo "main.dart":

import 'package:flutter/material.dart';
import 'telas/home.dart';
import 'telas/postar.dart';
import 'telas/perfil.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Navegação',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int telaAtual = 0;

  void trocandoTela(int novaTela) {
    setState(() {
      telaAtual = novaTela;
    });
  }

  final List<Widget> telas = [
    const Home(),
    const Postar(),
    const Perfil(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Navegação'),
      ),
      body: telas[telaAtual],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: telaAtual,
        onTap: trocandoTela,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            label: "Home",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.add_a_photo_outlined),
            label: "Postar",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person_2_outlined),
            label: "Perfil",
          ),
        ],
      ),
    );
  }
} 

Conclusão

Acho super interessante essa solução e como ela funciona. Existem diversos aplicativos no mercado que utilizam essa solução, como o Instagram, o Spotify ou o X, antigo Twitter. No sistema iOS é comum de termos esse tipo de navegação em aplicativos internos também. Com essa forma de se navegar o usuário poder ter acesso a todas as funções do aplicativo sem precisar forçar a mão e os dedos para alcançar algum botão. Então é isso galera, espero que tenham gostado da dica e até a próxima!

Sobre o autor
Cod3r

Cod3r

Com mais de 400 mil alunos, a Cod3r é uma das principais escolas de tecnologia do País. Um de seus produtos mais importantes é a Formação DEV, com objetivo de preparar os profissionais para o mercado.

Ótimo! Inscreveu-se com sucesso.

Bem-vindo de volta! Registou-se com sucesso.

Assinou com sucesso o Blog Formação DEV .

Sucesso! Verifique o seu e-mail para obter o link mágico para se inscrever.

As suas informações de pagamento foram atualizadas.

Seu pagamento não foi atualizado.