Mobile

30 mai, 2019

Flutter – Lista básica com ListView – Parte 03

Publicidade

Dando continuidade à série Flutter de criação de listas com Listview, hoje usaremos como exemplo o construtor ListView.builder para exibir uma grande quantidade de itens na lista de itens.

Caso tenha perdido os artigos anteriores, confira:

Para exibir uma lista de itens com uma grande quantidade de itens, podemos usar o construtor ListView.builder.

A principal diferença entre ListView e ListView.builder é que o construtor ListView padrão requer que criemos todos os itens de uma só vez, enquanto o construtor ListView.builder criará itens à medida em que eles forem rolados para a tela, como por demanda.

Criando um novo projeto Flutter

No VS Code abra a paleta de comandos (Ctrl + Shift + P) e digite flutter.

A seguir, clique em New Project, informe o nome listviewbuilder e escolha a pasta onde o projeto será criado.

Como vamos exibir uma imagem local (planeta1.jpg) em nossa aplicação, precisamos criar uma pasta assets na raiz do projeto e copiar a imagem que vamos exibir para essa pasta (você pode usar qualquer nome de pasta).

Para poder exibir a imagem em nossa aplicação Flutter, precisamos adicionar o nome dessa imagem dentro do arquivo pubspec.yaml.

Adicione a seguinte linha de código dentro do arquivo pubspec.yaml.

Ao final, nosso projeto terá a seguinte estrutura:

Criando o Stateful Widgets

No Flutter, tudo são Widgets, e podemos ter dois tipos de widgets: Stateless e Statefull, ou seja, sem estado e com estado.

Neste exemplo vamos criar um Stateful Widget, ou seja, um widget dinâmico que vai poder ser alterado por uma ação do usuário.

Substitua o código do arquivo main.dart pelo código abaixo:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyAppState();
  }
}
class _MyAppState extends State<MyApp> {
  List<String> _planetas = ['Saturno'];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.deepPurple),
      home: Scaffold(
        appBar: AppBar(title: Text('Lista de Planetasa')),
        body: Column(children: [
          Container(
              margin: EdgeInsets.all(10.0),
              child: RaisedButton(
                  color: Theme.of(context).primaryColor,
                  splashColor: Colors.blueGrey,
                  textColor: Colors.white,
                  onPressed: () {
                    setState(() {
                      _planetas.add('Saturno');
                    });
                  },
                  child: Text('Adicionar Planetas'))),
          Column(
              children: _planetas
                  .map((element) => Card(
                        child: Column(
                          children: <Widget>[
                            Image.asset('assets/planeta1.jpg'),
                            Text(element,
                                style: TextStyle(color: Colors.deepPurple))
                          ],
                        ),
                      ))
                  .toList()),
        ]),
      ),
    );
  }
}

Neste código criamos um widget com estado e, em seguida, configuramos o tema para o aplicativo Flutter. Em seguida, pegamos um botão criado e, quando o usuário pressiona o botão, adicionamos a imagem ao array e exibimos a imagem com o widget de Card.

Dessa forma, estamos exibindo dois itens: Image e Text.

Para executar, podemos pressionar F5, ou, no terminal de comandos, estando posicionado na pasta do projeto, basta digitar flutter run -d all.

Executando o projeto iremos obter o resultado abaixo:

Ao clicar no botão para Adicionar Planetas, veremos uma mensagem alertando que houve um overflow indicando que a imagem incluída passou os limites de exibição.

Resolvendo o problema

Para resolver este problema, temos que criar uma lista rolável usando o widget ListView.builder.

O construtor ListView.builder() é apropriado para exibições de lista com um número grande (ou infinito) de filhos, porque o construtor é chamado apenas para aqueles filhos visíveis.

Vamos fornecer um itemCount não nulo para melhorar a capacidade do ListView de estimar a extensão máxima de rolagem.

O retorno de chamada itemBuilder será chamado apenas com índices maiores ou iguais a zero e menores que itemCount.

Para fazer essa implementação vamos dividir o nosso projeto em dois arquivos:

  • planetas.dart
  • main.dart

O arquivo planetas.dart será responsável apenas por exibir os itens no widget Card com a ajuda do widget de construtor ListView.builder.

Inclua um novo arquivo chamado planetas.dart na pasta lib e a seguir inclua o código abaixo:

import 'package:flutter/material.dart';
class Planetas extends StatelessWidget {
  final List<String> planetas;
  Planetas(this.planetas);
  Widget _buildPlanetaItem(BuildContext context, int index) {
    return Card(
      child: Column(
        children: <Widget>[
          Image.asset('assets/planeta1.jpg'),
          Text(planetas[index], style: TextStyle(color: Colors.deepPurple))
        ],
      ),
    );
  }
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: _buildPlanetaItem,
      itemCount: planetas.length,
    );
  }
}

Esse código representa a classe Planetas, que possui um método chamado _buildPlanetaItem, que retorna o widget ListView.builder.

O widget ListView.builder usa dois argumentos:

  • Uma função que retorna o Widget
  • Um itemCount, que é o comprimento de uma matriz de planetas

A seguir vamos alterar o código do arquivo main.dart conforme abaixo:

import 'package:flutter/material.dart';
import './planetas.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyAppState();
  }
}
class _MyAppState extends State<MyApp> {
  List<String> _planetas = [];
  @override
  void initState() {
    super.initState();
    _planetas.add('Saturno');
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        theme: ThemeData(primarySwatch: Colors.deepPurple),
        home: Scaffold(
            appBar: AppBar(title: Text('Lista de Planetas')),
            body: Column(children: [
              Container(
                  margin: EdgeInsets.all(10.0),
                  child: RaisedButton(
                      color: Theme.of(context).primaryColor,
                      splashColor: Colors.blueGrey,
                      textColor: Colors.white,
                      onPressed: () {
                        setState(() {
                          _planetas.add('Saturno');
                        });
                      },
                      child: Text('Saturno'))),
              Expanded(child: Planetas(_planetas))
            ])));
  }
}

Aqui usamos o widget Expanded, que permite expandir um filho de uma Linha, Coluna ou Flex.

O uso de um widget Expanded faz com que o filho de uma Linha, Coluna ou Flex se expanda para preencher o espaço disponível no eixo primário (por exemplo, horizontalmente para uma linha ou verticalmente para uma coluna). Se vários filhos são expandidos, um espaço disponível é dividido entre eles de acordo com o fator flex.

Aqui, passamos o construtor de planetas importado com o argumento da matriz _planetas.

Agora, executando novamente ou apenas dando o hot reload, incluindo mais dois itens na lista veremos o seguinte resultado:

Temos agora que a lista vai exibindo os itens conforme vão sendo incluídos.

Esta é a maneira mais eficiente de exibir uma lista longa com o ListView, usando o construtor ListView.builder().

Na próxima parte do artigo veremos como obter dados de uma API REST no formato JSON via HTTP e exibir em um ListView.