Widgets com Scroll
SingleChildScrollView
Permite rolar conteúdo que excede o tamanho da tela:
SingleChildScrollView(
child: Column(
children: [
// Muitos widgets aqui
Text('Conteúdo 1'),
Text('Conteúdo 2'),
// ... mais conteúdo
],
),
)
ListView
ListView exibe uma lista rolável de widgets.
ListView com children
Usado quando você tem uma lista pequena e fixa de widgets (efeito similar ao uso de SingleChildScrollView):
ListView(
children: [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
)
ListView.builder
Usado para listas grandes ou dinâmicas. Mais eficiente em memória:
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
)
ListView.separated
Similar ao builder, mas permite adicionar separadores entre itens:
ListView.separated(
itemCount: 10,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
)
Diferenças importantes:
- children: Cria todos os widgets de uma vez. Use para listas pequenas (< 50 itens)
- builder: Cria widgets sob demanda (lazy loading). Use para listas grandes ou dinâmicas
- separated: Como builder, mas com separadores customizados
Quando usar SingleChildScrollView ou ListView?
-
SingleChildScrollView: Use quando você tem um conteúdo fixo e conhecido que precisa rolar, como um formulário longo, uma página de detalhes com múltiplas seções, ou qualquer layout customizado que não seja uma lista de itens repetidos. Cria todos os widgets de uma vez.
-
ListView: Use quando você tem uma lista de itens similares ou repetidos (como uma lista de produtos, mensagens, contatos). É mais eficiente para listas grandes porque cria widgets sob demanda (lazy loading) com
ListView.builder.
GridView
Exibe widgets em uma grade:
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: 20,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Item $index'),
),
);
},
)
Exercícios
-
ListView.builder: Crie uma lista usando
ListView.builderque exiba números de 1 a 100. Cada item deve mostrar "Item [número]". -
ListView.separated: Crie uma lista usando
ListView.separatedcom 10 itens. Adicione umDividercomo separador entre cada item. -
SingleChildScrollView: Crie um formulário longo usando
SingleChildScrollViewcom múltiplos campos de texto e botões. Demonstre que o conteúdo pode ser rolado. -
GridView: Crie um
GridViewcom 20 itens em uma grade de 2 colunas. Cada item deve ser umCardcom um número. -
ListTile interativo: Crie uma lista usando
ListView.buildercomListTileque responda a toques. Ao tocar em um item, exiba umSnackBarcom o nome do item.
Soluções
Ver solução do exercício 1
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('ListView.builder')),
body: ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item ${index + 1}'),
);
},
),
),
));
}
Ver solução do exercício 2
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('ListView.separated')),
body: ListView.separated(
itemCount: 10,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (context, index) {
return ListTile(
title: Text('Item ${index + 1}'),
);
},
),
),
));
}
Ver solução do exercício 3
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Formulário')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
TextField(decoration: InputDecoration(labelText: 'Nome')),
TextField(decoration: InputDecoration(labelText: 'Email')),
TextField(decoration: InputDecoration(labelText: 'Telefone')),
TextField(decoration: InputDecoration(labelText: 'Endereço')),
TextField(decoration: InputDecoration(labelText: 'Cidade')),
TextField(decoration: InputDecoration(labelText: 'Estado')),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: Text('Enviar'),
),
],
),
),
),
));
}
Ver solução do exercício 4
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('GridView')),
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
padding: EdgeInsets.all(10),
itemCount: 20,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Item ${index + 1}'),
),
);
},
),
),
));
}
Ver solução do exercício 5
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Lista Interativa')),
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item ${index + 1}'),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Item ${index + 1} selecionado')),
);
},
);
},
),
),
));
}