CollectionView no .NET MAUI
A CollectionView no .NET MAUI é o controle que exibe listas de dados com rolagem, seleção e layouts flexíveis, e ela define se o seu app vai rolar de forma fluida ou travar. Neste artigo, você sai do básico e entende como usá-la do jeito certo, com foco em listas modernas, performáticas e prontas para produção.
No eBook que acompanha este conteúdo, construímos um feed completo, da estrutura até a interface funcionando. Aqui, o objetivo é dar atenção especial a uma das peças mais importantes desse processo.
O que é a CollectionView no .NET MAUI
Praticamente todo app hoje tem algum tipo de lista. Seja um feed no estilo Instagram, uma timeline, uma lista de pedidos, um catálogo de produtos ou até logs internos, tudo gira em torno de mostrar dados de forma eficiente na tela.
É exatamente aí que a CollectionView entra. Segundo a documentação oficial da CollectionView, ela apresenta listas de dados com diferentes especificações de layout e busca ser uma alternativa mais flexível e performática à ListView.
A CollectionView no .NET MAUI não é só mais um componente de lista. Afinal, a forma como você a usa decide se o app fica escalável ou cheio de gambiarra, bonito ou difícil de manter.
A Microsoft também orienta quando usar outra opção. Se os dados não precisam de rolagem nem de seleção, um bindable layout resolve; caso contrário, a CollectionView no .NET MAUI é o caminho indicado.
Por que usar CollectionView em vez de ListView
O eBook deixa claro que a CollectionView é mais performática, flexível e preparada para virtualização. Na prática, isso significa:
- Melhor performance que a
ListView. - Renderização inteligente, com virtualização.
- Layouts flexíveis em lista, grade ou rolagem horizontal.
- Controle visual total por meio de
DataTemplate.
Além disso, a escolha deixou de ser apenas uma questão de preferência. No .NET 10, a Microsoft marcou a ListView como obsoleta, junto com células como TextCell e ViewCell, e recomenda a CollectionView no lugar.
Outra diferença importante envolve o cache. A ListView exigia configurar a propriedade CachingStrategy, enquanto a CollectionView usa automaticamente a virtualização dos controles nativos de cada plataforma.
Resumindo, a CollectionView no .NET MAUI é o padrão atual para qualquer lista. Se você ainda compara frameworks móveis, o artigo .NET MAUI vs Flutter ajuda a entender o ecossistema.
Estrutura básica da CollectionView no .NET MAUI
Veja um exemplo direto ao ponto. A propriedade ItemsSource recebe a coleção, e o ItemTemplate define a aparência de cada item.
<CollectionView ItemsSource="{Binding Posts}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Post">
<Border Padding="10" Margin="5">
<VerticalStackLayout>
<Label Text="{Binding Title}" FontAttributes="Bold" />
<Label Text="{Binding Content}" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Com poucas linhas, a CollectionView no .NET MAUI já exibe a lista de forma simples, limpa e funcional. Repare que o exemplo usa Border em vez de Frame, porque o Frame ficou obsoleto no .NET MAUI 9 e deve sair em uma versão futura.
Na migração, a propriedade BorderColor do Frame vira Stroke, e o CornerRadius passa a fazer parte do StrokeShape. Em alguns casos, também vale repetir o valor de Margin no Padding.
Virtualização da CollectionView no .NET MAUI
O segredo da performance está na virtualização. A CollectionView renderiza apenas o que aparece na tela e reaproveita as views conforme o usuário rola a lista.
Isso muda tudo na CollectionView no .NET MAUI. Entre os benefícios, estão:
- Menor consumo de memória.
- Rolagem fluida.
- Melhor desempenho em listas grandes.
Abordagens antigas renderizavam todos os itens de uma vez, então uma lista com milhares de registros pesava na memória. Com a virtualização, o custo fica proporcional ao que cabe na tela.
No .NET 10, os handlers otimizados que eram opcionais no .NET 9 passaram a ser o padrão no iOS e no Mac Catalyst. Segundo a Microsoft, essa mudança trouxe mais desempenho e estabilidade para a CollectionView nessas plataformas.
Como funciona o ItemSizingStrategy
Por padrão, a CollectionView mede cada item individualmente. Esse comportamento vem da propriedade ItemSizingStrategy, cujo valor padrão é MeasureAllItems.
Quando todos os itens têm o mesmo tamanho, você pode trocar para MeasureFirstItem. Assim, o controle mede apenas o primeiro item e aplica o mesmo tamanho aos demais.
<CollectionView ItemsSource="{Binding Posts}"
ItemSizingStrategy="MeasureFirstItem">
<!-- template com itens de altura uniforme -->
</CollectionView>
A documentação destaca que essa estratégia aumenta a performance quando o tamanho dos itens é uniforme. Por outro lado, em listas com alturas variadas, mantenha o padrão para evitar cortes no layout.
Erro clássico que mata a performance
O eBook alerta sobre um problema muito comum: evite aninhar a CollectionView dentro de um ScrollView. Essa combinação gera problemas de performance, porque duas camadas disputam a rolagem.
Veja a forma errada:
<!-- Errado: ScrollView envolvendo a CollectionView -->
<ScrollView>
<CollectionView />
</ScrollView>
Quando a CollectionView no .NET MAUI fica dentro de um ScrollView, ela pode perder a referência de espaço disponível. Então, o controle tenta crescer para caber todos os itens, e a virtualização deixa de funcionar como deveria.
A documentação aponta um problema parecido com VerticalStackLayout e StackLayout. Nesses contêineres, a CollectionView pode parar de rolar, ignorar o método ScrollTo ou limitar a quantidade de itens exibidos; a recomendação é trocar o contêiner por um Grid.
Dicas de performance para CollectionView no .NET MAUI
Com a estrutura certa, o próximo passo envolve cuidar de cada item da CollectionView no .NET MAUI. As dicas a seguir separam uma lista amadora de uma lista em nível profissional.
Use ObservableCollection
A ObservableCollection<T> avisa a interface sempre que um item entra ou sai da coleção. Assim, a tela se atualiza sozinha e você evita refresh manual.
public ObservableCollection<Post> Posts { get; } = [];
Em outras palavras, a interface reage automaticamente às mudanças. Só lembre que trocar a coleção inteira exige notificar a propriedade, então prefira manter a mesma instância e alterar o conteúdo.
Nada de lógica pesada na View
Evite colocar cálculos dentro do binding ou de conversores complexos. Cada item visível executa essa lógica, e o custo se multiplica durante a rolagem.
<!-- Evite: lógica complexa resolvida durante o binding -->
<Label Text="{Binding Post, Converter={StaticResource CalculateSomethingComplexConverter}}" />
Prefira expor uma propriedade pronta no modelo ou na ViewModel:
public string FormattedText => $"{Title} - {Author}";
<Label Text="{Binding FormattedText}" />
A regra é simples: a View exibe, a ViewModel pensa.
Simplifique a hierarquia visual
Layouts aninhados em excesso aumentam o trabalho de medição de cada item. Por isso, evite estruturas como esta:
<!-- Ruim: camadas desnecessárias -->
<StackLayout>
<StackLayout>
<StackLayout>
<!-- conteúdo -->
</StackLayout>
</StackLayout>
</StackLayout>
Prefira um único VerticalStackLayout ou um Grid bem definido. Menos camadas significam renderização mais rápida.
Controle as imagens
Imagens costumam ser o item mais pesado de um feed montado com a CollectionView no .NET MAUI. Então, defina a altura e o modo de ajuste para o layout não precisar recalcular tudo quando o arquivo terminar de carregar.
<Image Source="{Binding ImageUrl}"
HeightRequest="200"
Aspect="AspectFill" />
Entre as boas práticas, vale definir a altura, evitar imagens gigantes e usar cache sempre que possível. Além disso, servir as imagens já redimensionadas pelo backend reduz o consumo de memória no dispositivo.
Limite o conteúdo dos textos
Textos longos geram itens altos e medições mais caras. Com MaxLines e LineBreakMode, você corta o excesso e mantém o layout previsível.
<Label Text="{Binding Content}"
MaxLines="3"
LineBreakMode="TailTruncation" />
Isso evita layouts pesados e melhora a rolagem. Se o usuário quiser ler tudo, a tela de detalhe pode mostrar o texto completo.
O mesmo raciocínio vale para descrições, comentários e qualquer campo de tamanho imprevisível. Quanto mais previsível a altura de cada item, menos trabalho o controle tem para medir e posicionar a lista.
Reduza bindings desnecessários
Cada binding tem um custo, e esse custo se repete em todos os itens visíveis. Por exemplo, três labels com três bindings podem virar uma só:
<!-- Excesso de bindings -->
<Label Text="{Binding A}" />
<Label Text="{Binding B}" />
<Label Text="{Binding C}" />
<!-- Melhor: uma propriedade de resumo -->
<Label Text="{Binding Summary}" />
Nem sempre essa troca faz sentido, porque estilos diferentes exigem elementos separados. Mesmo assim, vale revisar o template em busca de bindings que só existem por hábito.
Use compiled bindings
Na CollectionView no .NET MAUI, os compiled bindings resolvem as expressões em tempo de compilação, e não por reflexão em tempo de execução. Para ativá-los, informe o tipo do contexto com x:DataType no DataTemplate.
<DataTemplate x:DataType="models:Post">
<Label Text="{Binding Title}" />
</DataTemplate>
A documentação recomenda anotar todo DataTemplate com o x:DataType correto. Caso contrário, o compilador emite avisos como o XC0022 e o binding volta a usar reflexão.
Use DataTemplate corretamente
O eBook destaca que o DataTemplate separa dados, layout e responsabilidade da View. Veja um exemplo mais profissional, já reunindo as dicas anteriores:
<DataTemplate x:DataType="models:Post">
<Border Margin="12"
Stroke="#E0E0E0"
StrokeShape="RoundRectangle 20">
<VerticalStackLayout Spacing="10">
<Image Source="{Binding ImageUrl}" HeightRequest="200" />
<Label Text="{Binding Title}"
FontAttributes="Bold"
FontSize="18" />
<Label Text="{Binding Content}"
MaxLines="3" />
<Label Text="{Binding Author}"
FontSize="12"
TextColor="Gray" />
</VerticalStackLayout>
</Border>
</DataTemplate>
Layouts da CollectionView no .NET MAUI
A flexibilidade de layout é uma das grandes vantagens do controle. Por padrão, a CollectionView exibe uma lista vertical, mas a propriedade ItemsLayout aceita outras opções.
- Lista vertical, que cresce para baixo.
- Lista horizontal, que cresce para o lado.
- Grade vertical, com várias colunas.
- Grade horizontal, com várias linhas.
<CollectionView ItemsSource="{Binding Posts}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="20"
HorizontalItemSpacing="30" />
</CollectionView.ItemsLayout>
</CollectionView>
Com isso, a mesma fonte de dados pode virar um feed, uma galeria ou um carrossel apenas com a troca do layout. Se o seu app também roda no desktop, o artigo sobre .NET MAUI no Windows e no macOS mostra como aproveitar telas maiores.
Seleção e lista vazia na CollectionView no .NET MAUI
Duas necessidades aparecem em quase todo app: permitir que o usuário selecione itens e mostrar algo útil quando a lista não tem dados. A CollectionView no .NET MAUI resolve as duas sem componentes extras.
Para a seleção, a propriedade SelectionMode aceita os valores None, Single e Multiple. Em seguida, você liga o item escolhido à ViewModel com SelectedItem ou reage à mudança com SelectionChangedCommand.
<CollectionView ItemsSource="{Binding Posts}"
SelectionMode="Single"
SelectedItem="{Binding SelectedPost}"
SelectionChangedCommand="{Binding OpenPostCommand}">
<!-- template do item -->
</CollectionView>
Diferente da ListView, a CollectionView não traz separadores prontos entre as linhas. Portanto, se o design pedir uma linha divisória, inclua esse elemento no próprio template do item.
Já para listas vazias, use a propriedade EmptyView. Ela aceita um texto simples ou uma view completa, exibida apenas quando a fonte de dados não tem itens.
<CollectionView ItemsSource="{Binding Posts}">
<CollectionView.EmptyView>
<Label Text="No posts yet."
HorizontalOptions="Center"
VerticalOptions="Center" />
</CollectionView.EmptyView>
</CollectionView>
Com isso, você evita telas em branco e comunica o estado da lista de forma clara. Além disso, a mensagem pode orientar o usuário sobre o próximo passo, como criar o primeiro registro.
MVVM com CollectionView no .NET MAUI
A performance da CollectionView no .NET MAUI não depende apenas do XAML. Afinal, a arquitetura da tela também pesa, e o padrão MVVM ajuda a manter cada parte no seu lugar.
BindingContext = new FeedViewModel();
A ViewModel é o cérebro da tela. Ela expõe os dados e os comandos, enquanto a View apenas desenha o que recebe.
Separe responsabilidades
Cada camada tem uma função clara no padrão MVVM:
| Camada | Responsabilidade |
|---|---|
| Model | Dados |
| View | Interface |
| ViewModel | Lógica de apresentação |
Essa separação facilita testes, evita lógica espalhada pelo code-behind e deixa o template do item mais leve.
Na prática, a CollectionView no .NET MAUI recebe da ViewModel apenas dados prontos para exibição. Assim, qualquer regra de formatação ou filtragem acontece fora do template e roda uma única vez, e não a cada item renderizado.
Use Commands
Ações da tela, como carregar posts, devem ficar em comandos expostos pela ViewModel. Assim, a View apenas dispara a ação por binding.
public ICommand LoadPostsCommand { get; }
Exemplo completo de CollectionView no .NET MAUI
Agora, junte as peças em um exemplo completo. Primeiro, o modelo e a ViewModel:
public class Post
{
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
}
public class FeedViewModel
{
public ObservableCollection<Post> Posts { get; } = [];
public ICommand LoadPostsCommand { get; }
public FeedViewModel()
{
LoadPostsCommand = new Command(LoadPosts);
LoadPosts();
}
private void LoadPosts()
{
// Dados de exemplo; em produção, viriam de uma API
Posts.Add(new Post { Title = "Post 1", Content = "Content", Author = "Admin" });
Posts.Add(new Post { Title = "Post 2", Content = "Content", Author = "Team" });
}
}
Em seguida, a View:
<CollectionView ItemsSource="{Binding Posts}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Post">
<Border Margin="10" Padding="10">
<VerticalStackLayout>
<Label Text="{Binding Title}" FontAttributes="Bold" />
<Label Text="{Binding Content}" />
<Label Text="{Binding Author}" FontSize="12" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
O exemplo usa ObservableCollection, comando, compiled bindings e um template enxuto. Ou seja, ele aplica as principais práticas deste artigo em poucas linhas.
Próximos passos com CollectionView no .NET MAUI
Depois de dominar a base, alguns recursos levam o feed da CollectionView no .NET MAUI a outro nível. Entre os mais comuns, estão:
- Infinite scroll, com paginação conforme o usuário se aproxima do fim da lista.
- Pull to refresh, para recarregar o conteúdo com um gesto.
- Skeleton loading, para mostrar a estrutura enquanto os dados chegam.
- Feed completo no estilo Instagram.
Para o infinite scroll, a CollectionView oferece a propriedade RemainingItemsThreshold e o comando RemainingItemsThresholdReachedCommand. Já o pull to refresh normalmente usa o controle RefreshView envolvendo a lista.
Esses temas merecem um aprofundamento próprio. Mesmo assim, todos dependem da mesma base: virtualização preservada, templates leves e uma ViewModel bem organizada.
Conclusão
A CollectionView não é só uma lista. Ela é a base da interface moderna no MAUI.
Se você usar MVVM, binding eficiente, templates bem estruturados e hierarquia leve, ganha performance, escalabilidade e código limpo. Além disso, evita armadilhas como o ScrollView aninhado e o Frame obsoleto.
O maior erro não é usar CollectionView. É usá-la como se fosse uma ListView antiga.
Quando você trata a CollectionView no .NET MAUI como um componente moderno, pensando em arquitetura e performance, o seu app muda completamente de nível.
FAQ
A ListView ainda pode ser usada no .NET MAUI?
Ela ainda existe, mas a Microsoft a marcou como obsoleta no .NET 10. A recomendação oficial é migrar para a CollectionView.
Posso colocar uma CollectionView dentro de um ScrollView?
Não é recomendado, porque a combinação prejudica a virtualização e a rolagem. Use as propriedades Header e Footer da própria CollectionView.
Quando usar MeasureFirstItem?
Use quando todos os itens da lista têm o mesmo tamanho. Nesse caso, o controle mede só o primeiro item e ganha performance.
Por que trocar Frame por Border?
O Frame ficou obsoleto no .NET MAUI 9 e deve ser removido no futuro. O Border oferece o mesmo resultado com as propriedades Stroke e StrokeShape.
Como implementar paginação na CollectionView?
Use a propriedade RemainingItemsThreshold com o comando RemainingItemsThresholdReachedCommand. Assim, a ViewModel carrega mais itens quando o usuário se aproxima do fim da lista.