ListView
A UI do aplicativo multiplataforma .NET (.NET MAUI) ListView exibe uma lista vertical rolável de itens de dados selecionáveis. Enquanto ListView gerencia a aparência da lista, a aparência de cada item da lista é definida por um DataTemplate que usa um Cell para exibir itens. .NET MAUI inclui tipos de células para exibir combinações de texto e imagens, e você também pode definir células personalizadas que exibem qualquer conteúdo desejado. ListView também inclui suporte para exibição de cabeçalhos e rodapés, dados agrupados, puxar para atualizar e itens de menu de contexto.
A classe ListView deriva da classe ItemsView<Cell>
, da qual herda as seguintes propriedades:
ItemsSource
, do tipoIEnumerable
, especifica a coleção de itens a serem exibidos e tem um valor padrão denull
.ItemTemplate
, do tipo DataTemplate, especifica o modelo a ser aplicado a cada item na coleção de itens a serem exibidos.
ListView define as propriedades a seguir:
Footer
, do tipoobject
, especifica a string ou visualização que será exibida no final da lista.FooterTemplate
, do tipo DataTemplate, especifica o DataTemplate a ser usado para formatar oFooter
.GroupHeaderTemplate
, do tipo DataTemplate, define o DataTemplate utilizado para definir a aparência do cabeçalho de cada grupo. Essa propriedade é mutuamente exclusiva com a propriedadeGroupDisplayBinding
. Portanto, definir essa propriedade definiráGroupDisplayBinding
comonull
.HasUnevenRows
, do tipobool
, indica se os itens da lista podem ter linhas de alturas diferentes. O valor padrão dessa propriedade éfalse
.Header
, do tipoobject
, especifica a cadeia de caracteres ou visualização que será exibida no início da lista.HeaderTemplate
, do tipo DataTemplate, especifica o DataTemplate a ser usado para formatar oHeader
.HorizontalScrollBarVisibility
, do tipoScrollBarVisibility
, indica quando a barra de rolagem horizontal ficará visível.IsGroupingEnabled
, do tipobool
, indica se os dados subjacentes devem ser exibidos em grupos. O valor padrão dessa propriedade éfalse
.IsPullToRefreshEnabled
, do tipobool
, indica se o usuário pode deslizar para baixo para fazer com que ListView atualize seus dados. O valor padrão dessa propriedade éfalse
.IsRefreshing
, do tipobool
, indica se o ListView está sendo atualizado no momento. O valor padrão dessa propriedade éfalse
.RefreshCommand
, do tipo ICommand, representa o comando que será executado quando uma atualização for acionada.RefreshControlColor
, do tipo Color, determina a cor da visualização de atualização mostrada enquanto ocorre uma atualização.RowHeight
, do tipoint
, determina a altura de cada linha quandoHasUnevenRows
éfalse
.SelectedItem
, do tipoobject
, representa o item atualmente selecionado noListView.SelectionMode
, do tipoListViewSelectionMode
, indica se os itens podem ser selecionados no ListView ou não. O valor padrão dessa propriedade éSingle
.SeparatorColor
, do tipo Color, define a cor da barra que separa os itens da lista.SeparatorVisibility
, do tipoSeparatorVisibility
, define se os separadores são visíveis entre os itens.VerticalScrollBarVisibility
, do tipoScrollBarVisibility
, indica quando a barra de rolagem vertical ficará visível.
Todas essas propriedades são apoiadas por objetos BindableProperty, o que significa que podem ser alvos de vinculações de dados e estilizadas.
Além disso, ListView define as seguintes propriedades que não são apoiadas por objetos BindableProperty:
GroupDisplayBinding
, do tipoBindingBase
, a ligação a ser usada para exibir o cabeçalho do grupo. Essa propriedade é mutuamente exclusiva com a propriedadeGroupHeaderTemplate
. Portanto, definir essa propriedade definiráGroupHeaderTemplate
comonull
.GroupShortNameBinding
, do tipoBindingBase
, a ligação do nome a ser exibido em listas de atalhos agrupadas.CachingStrategy
, do tipoListViewCachingStrategy
, define a estratégia de reutilização de células do ListView. Trata-se de uma propriedade somente leitura.
ListView define os seguintes eventos:
ItemAppearing
, que é gerado quando a representação visual de um item está sendo adicionada ao layout visual do ListView. O objetoItemVisibilityEventArgs
que acompanha esse evento define as propriedadesItem
eIndex
.ItemDisappearing
, que é gerado quando a representação visual de um item está sendo removida do layout visual do ListView. O objetoItemVisibilityEventArgs
que acompanha esse evento define as propriedadesItem
eIndex
.ItemSelected
, que é gerado quando um novo item na lista é selecionado. O objetoSelectedItemChangedEventArgs
que acompanha esse evento define as propriedadesSelectedItem
eSelectedItemIndex
.ItemTapped
, que surge quando um item no ListView é tocado. O objetoItemTappedEventArgs
que acompanha esse evento define as propriedadesGroup
,Item
, eItemIndex
.Refreshing
, que é gerado quando uma operação pull to refresh é acionada no ListView.Scrolled
, . O objetoScrolledEventArgs
que acompanha esse evento define as propriedadesScrollX
eScrollY
.ScrollToRequested
. O objetoScrollToRequestedEventArgs
que acompanha esse evento define as propriedades Element,Mode
,Position
,ScrollX
,ScrollY
eShouldAnimate
.
Preencher um ListView com dados
Um ListView é preenchido com dados definindo sua propriedade ItemsSource
para qualquer coleção que implemente IEnumerable
.
Importante
Se o ListView for necessário para atualizar conforme os itens são adicionados, removidos ou alterados na coleção subjacente, a coleção subjacente deverá ser uma coleção IEnumerable
que envia notificações de alteração de propriedade, como ObservableCollection
.
ListView pode ser preenchido com dados usando vinculação de dados para vincular sua propriedade ItemsSource
a uma coleção IEnumerable
. No XAML, isso é conseguido com a extensão de marcação Binding
:
<ListView ItemsSource="{Binding Monkeys}" />
Este é o código C# equivalente:
ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
Nesse exemplo, os dados da propriedade ItemsSource
são vinculados à propriedade Monkeys
do viewmodel conectado.
Observação
As vinculações compiladas podem ser habilitadas para melhorar o desempenho da vinculação de dados em aplicativos .NET MAUI. Para obter mais informações, confira Associações compiladas.
Para obter mais informações sobre vinculação de dados, veja Vinculação de dados.
Definir a aparência do item
A aparência de cada item no ListView pode ser definida definindo a propriedade ItemTemplate
como um DataTemplate:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Os elementos especificados no DataTemplate definem a aparência de cada item da lista, e o filho do DataTemplate deve ser um objeto Cell. No exemplo, o layout dentro do DataTemplate é gerenciado por um Grid. O Grid contém um objeto Image e dois objetos Label, todos vinculados às propriedades da classe Monkey
:
public class Monkey
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}
A captura de tela a seguir mostra o resultado da modelagem de cada item da lista:
Para obter mais informações sobre modelos de dados, consulte Modelos de dados.
Cells
A aparência de cada item em um ListView é definida por um DataTemplate e o DataTemplate deve fazer referência a uma classe Cell para exibir os itens. Cada célula representa um item de dados no ListView. O .NET MAUI inclui as seguintes células internas:
- TextCell, que exibe texto primário e secundário em linhas separadas.
- ImageCell, que exibe uma imagem com texto primário e secundário em linhas separadas.
- SwitchCell, que exibe texto e uma alternância que pode ser ligada ou desligada.
- EntryCell, que exibe um rótulo e um texto que pode ser editado.
- ViewCell, que é uma célula personalizada cuja aparência é definida por um View. Esse tipo de célula deve ser usado quando você quiser definir totalmente a aparência de cada item em um ListView.
Normalmente, SwitchCell e EntryCell serão usados apenas em um TableView e não serão usados em um ListView. Para obter mais informações sobre SwitchCell e EntryCell, veja TableView.
Célula de texto
Uma TextCell exibe o texto primário e secundário em linhas separadas. TextCell define as propriedades a seguir:
Text
, do tipostring
, define o texto primário a ser exibido.TextColor
, do tipo Color, representa a cor do texto primário.Detail
, do tipostring
, define o texto secundário a ser exibido.DetailColor
, do tipo Color, indica a cor do texto secundário.Command
, do tipo ICommand, define o comando que é executado quando a célula é tocada.CommandParameter
, do tipoobject
, representa o parâmetro que é passado para o comando.
Essas propriedades são apoiadas por objetos BindableProperty, o que significa que podem ser alvos de associações de dados e ser estilizada.
O exemplo a seguir mostra o uso de um TextCell para definir a aparência dos itens em um ListView:
<ListView ItemsSource="{Binding Food}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A captura de tela a seguir mostra a aparência da célula resultante:
Célula de imagem
Um ImageCell exibe uma imagem com texto primário e secundário em linhas separadas. ImageCell herda as propriedades de TextCell e define a propriedade ImageSource, do tipo ImageSource, que especifica a imagem a ser exibida na célula. Essa propriedade é apoiada por um objeto BindableProperty, o que significa que ela pode ser o alvo de associações de dados e ser estilizada.
O exemplo a seguir mostra o uso de um ImageCell para definir a aparência dos itens em um ListView:
<ListView ItemsSource="{Binding Food}">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource="{Binding Image}"
Text="{Binding Name}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A captura de tela a seguir mostra a aparência da célula resultante:
Exibir célula
Um ViewCell é uma célula personalizada cuja aparência é definida por um View. ViewCell define uma propriedade View, do tipo View, que define a exibição que representa o conteúdo da célula. Essa propriedade é apoiada por um objeto BindableProperty, o que significa que ela pode ser o alvo de associações de dados e ser estilizada.
Observação
A propriedade View é a propriedade de conteúdo da classe ViewCell e, portanto, não precisa ser definida explicitamente no XAML.
O exemplo a seguir mostra o uso de um ViewCell para definir a aparência dos itens em um ListView:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Dentro do ViewCell, o layout pode ser gerenciado por qualquer layout .NET MAUI. Nesse exemplo, o layout é gerenciado por um Grid. O Grid contém um objeto Image e dois objetos Label, todos vinculados às propriedades da classe Monkey
.
A captura de tela a seguir mostra o resultado da modelagem de cada item da lista:
Escolher a aparência do item em tempo de execução
A aparência de cada item no ListView pode ser escolhida em tempo de execução, com base no valor do item, definindo a propriedade ItemTemplate
como um objeto DataTemplateSelector:
<ContentPage ...
xmlns:templates="clr-namespace:ListViewDemos.Templates">
<ContentPage.Resources>
<DataTemplate x:Key="AmericanMonkeyTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="OtherMonkeyTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<templates:MonkeyDataTemplateSelector x:Key="MonkeySelector"
AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
</ContentPage.Resources>
<Grid Margin="20">
<ListView ItemsSource="{Binding Monkeys}"
ItemTemplate="{StaticResource MonkeySelector}" />
</Grid>
</ContentPage>
A propriedade ItemTemplate
é definida como um objeto MonkeyDataTemplateSelector
. O exemplo a seguir mostra a classe MonkeyDataTemplateSelector
:
public class MonkeyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate AmericanMonkey { get; set; }
public DataTemplate OtherMonkey { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
}
}
A classe MonkeyDataTemplateSelector
define propriedades AmericanMonkey
e OtherMonkey
DataTemplate que são configuradas para diferentes modelos de dados. A substituição OnSelectTemplate
retorna o modeloAmericanMonkey
, que exibe o nome e a localização do macaco em azul-petróleo, quando o nome do macaco contém "América". Quando o nome do macaco não contém "América", a substituição OnSelectTemplate
retorna o modelo OtherMonkey
, que exibe o nome e a localização do macaco em prata:
Para obter mais informações sobre seletores de modelo de dados, consulte Criar um DataTemplateSelector.
Responder à seleção do item
Por padrão, ListView a seleção está habilitada. No entanto, esse comportamento pode ser alterado definindo a propriedade SelectionMode
. A enumeração ListViewSelectionMode
define os seguintes membros:
None
– indica que os itens não podem ser selecionados.Single
– indica que um único item pode ser selecionado, com o item selecionado sendo destacado. Este é o valor padrão.
ListView define um evento ItemSelected
que é gerado quando a propriedade SelectedItem
é alterada, seja porque o usuário seleciona um item da lista ou quando um aplicativo define a propriedade. O objeto SelectedItemChangedEventArgs
que acompanha esse evento possui propriedades SelectedItem
e SelectedItemIndex
.
Quando a propriedade SelectionMode
é definida como Single
, um único item no ListView pode ser selecionado. Quando um item é selecionado, a propriedade SelectedItem
será definida com o valor do item selecionado. Quando essa propriedade altera, o evento ItemSelected
é gerado.
O exemplo a seguir mostra um ListView que pode responder à seleção de um único item:
<ListView ItemsSource="{Binding Monkeys}"
ItemSelected="OnItemSelected">
...
</ListView>
Nesse exemplo, o manipulador de eventos OnItemSelected
é executado quando o evento ItemSelected
é acionado, com o manipulador de eventos recuperando o item selecionado:
void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
Monkey item = args.SelectedItem as Monkey;
}
A captura de tela a seguir mostra a seleção de um único item em um ListView:
Desmarcar a seleção
A propriedade SelectedItem
pode ser limpa definindo-a, ou o objeto ao qual ela está vinculada, como null
.
Desativar seleção
ListView a seleção está habilitada por padrão. No entanto, ele pode ser desativado definindo a propriedade SelectionMode
como None
:
<ListView ...
SelectionMode="None" />
Quando a propriedade SelectionMode
é definida como None
, os itens em ListView não podem ser selecionados, a propriedade SelectedItem
permanecerá null
e o evento ItemSelected
não será acionado.
Dados de cache
ListView é uma visualização poderosa para exibir dados, mas tem algumas limitações. O desempenho da rolagem pode ser prejudicado ao usar células personalizadas, especialmente quando elas contêm hierarquias de visualização profundamente aninhadas ou usam determinados layouts que exigem medições complexas. Felizmente, existem técnicas que você pode usar para evitar um desempenho ruim.
Um ListView é frequentemente usado para exibir muito mais dados do que cabe na tela. Por exemplo, um aplicativo de música pode ter uma biblioteca de músicas com milhares de entradas. Criar um item para cada entrada desperdiçaria memória valiosa e teria um desempenho insatisfatório. Criar e destruir linhas constantemente exigiria que o aplicativo instanciasse e limpasse objetos constantemente, o que também teria um desempenho insatisfatório.
Para conservar memória, os ListView equivalentes nativos de cada plataforma possuem recursos integrados para reutilização de linhas. Apenas as células visíveis na tela são carregadas na memória e o conteúdo é carregado nas células existentes. Esse padrão evita que o aplicativo instancie milhares de objetos, economizando tempo e memória.
O .NET MAUI permite ListView a reutilização de células por meio da ListViewCachingStrategy
enumeração, que define os seguintes membros:
RetainElement
, especifica que o ListView irá gerar uma célula para cada item da lista.RecycleElement
, especifica que ListView tentará minimizar o consumo de memória e a velocidade de execução reciclando as células da lista.RecycleElementAndDataTemplate
, comoRecycleElement
ao mesmo tempo que garante que quando um ListView usa um DataTemplateSelector, DataTemplate os objetos são armazenados em cache pelo tipo de item na lista.
Reter elementos
A estratégia de cache RetainElement
especifica que ListView gerará uma célula para cada item da lista e é o comportamento ListView padrão. Deve ser usado nas seguintes circunstâncias:
- Cada célula possui um grande número de ligações (20-30+).
- O modelo de célula muda frequentemente.
- Os testes revelam que a estratégia de cache
RecycleElement
resulta em uma velocidade de execução reduzida.
É importante reconhecer as consequências da RetainElement
estratégia de cache ao trabalhar com células customizadas. Qualquer código de inicialização de célula precisará ser executado para cada criação de célula, o que pode ocorrer várias vezes por segundo. Nessa circunstância, as técnicas de layout que funcionavam bem em uma página, como o uso de vários objetos Grid aninhados, tornam-se gargalos de desempenho quando são configuradas e destruídas em tempo real à medida que o usuário rola.
Reciclar elementos
A estratégia de cache RecycleElement
especifica que o ListView tentará minimizar o consumo de memória e a velocidade de execução reciclando as células da lista. Esse modo nem sempre oferece melhoria de desempenho e testes devem ser realizados para determinar quaisquer melhorias. No entanto, é a escolha preferida e deve ser usada nas seguintes circunstâncias:
- Cada célula possui um número pequeno a moderado de ligações.
- O
BindingContext
de cada célula define todos os dados da célula. - Cada célula é bastante semelhante, com o modelo de célula inalterado.
Durante a virtualização, a célula terá seu contexto de ligação atualizado e, portanto, se um aplicativo usar esse modo, ele deverá garantir que as atualizações do contexto de ligação sejam tratadas adequadamente. Todos os dados sobre a célula devem vir do contexto de ligação ou poderão ocorrer erros de consistência. Esse problema pode ser evitado usando a vinculação de dados para exibir os dados da célula. Como alternativa, os dados da célula devem ser definidos na substituição OnBindingContextChanged
, em vez de no construtor da célula personalizada, conforme mostrado no exemplo a seguir:
public class CustomCell : ViewCell
{
Image image = null;
public CustomCell()
{
image = new Image();
View = image;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var item = BindingContext as ImageItem;
if (item != null)
{
image.Source = item.ImageUrl;
}
}
}
Reciclar elementos com um DataTemplateSelector
Quando um ListView usa um DataTemplateSelector para selecionar um DataTemplate, a RecycleElement
estratégia de cache não armazena em cache DataTemplate objetos. Em vez disso, um DataTemplate é selecionado para cada item de dados da lista.
Observação
A estratégia de cache RecycleElement
exige que, quando um DataTemplateSelector for solicitado a selecionar um DataTemplate, cada DataTemplate retorne o mesmo tipo ViewCell. Por exemplo, dado um ListView com um DataTemplateSelector que pode retornar MyDataTemplateA
(onde MyDataTemplateA
retorna um ViewCell do tipo MyViewCellA
) ou MyDataTemplateB
(onde MyDataTemplateB
retorna um ViewCell do tipo MyViewCellB
), quando MyDataTemplateA
é retornado ele deve retornar MyViewCellA
ou uma exceção será lançado.
Reciclar elementos com DataTemplates
A estratégia de cache RecycleElementAndDataTemplate
baseia-se na estratégia de cache RecycleElement
garantindo adicionalmente que quando um ListView usa um DataTemplateSelector para selecionar um DataTemplate, DataTemplateobjetos são armazenados em cache pelo tipo de item na lista. Portanto, DataTemplate os objetos são selecionados uma vez por tipo de item, em vez de uma vez por instância de item.
Observação
A estratégia de cache RecycleElementAndDataTemplate
requer que DataTemplate os objetos retornados pelo DataTemplateSelector usem o construtor DataTemplate que recebe um Type
.
Defina a estratégia de cache
A estratégia de cache ListView pode ser definida em XAML definindo o atributo CachingStrategy
:
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Em C#, a estratégia de cache é definida por meio de uma sobrecarga de construtor:
ListView listView = new ListView(ListViewCachingStrategy.RecycleElement);
Defina a estratégia de cache em um ListView subclassificado
Definir o atributo CachingStrategy
do XAML em uma subclasse ListView não produzirá o comportamento desejado, porque não há propriedade CachingStrategy
em ListView. A solução para esse problema é especificar um construtor na subclasse ListView que aceite um parâmetro ListViewCachingStrategy
e o passe para a classe base:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
Em seguida, o valor de enumeração ListViewCachingStrategy
pode ser especificado em XAML usando o atributo x:Arguments
:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
Cabeçalhos e rodapés
ListView pode apresentar um cabeçalho e rodapé que rola com os itens da lista. O cabeçalho e o rodapé podem ser strings, visualizações ou objetos DataTemplate.
ListView define as seguintes propriedades para especificar o cabeçalho e o rodapé:
Header
, do tipoobject
, especifica a string, ligação ou visualização que será exibida no início da lista.HeaderTemplate
, do tipo DataTemplate, especifica o DataTemplate a ser usado para formatar oHeader
.Footer
, do tipoobject
, especifica a string, ligação ou visualização que será exibida no final da lista.FooterTemplate
, do tipo DataTemplate, especifica o DataTemplate a ser usado para formatar oFooter
.
Essas propriedades são apoiadas por objetos BindableProperty, o que significa que as propriedades podem ser alvos de vinculações de dados.
Exibir strings no cabeçalho e rodapé
As propriedades Header
e Footer
podem ser definidas como valores string
, conforme mostrado no exemplo a seguir:
<ListView ItemsSource="{Binding Monkeys}"
Header="Monkeys"
Footer="2022">
...
</ListView>
A captura de tela a seguir mostra o cabeçalho resultante:
Exibir visualizações no cabeçalho e rodapé
As propriedades Header
e Footer
podem ser definidas para uma visualização. Pode ser uma exibição única ou uma exibição que contém várias exibições filho. O exemplo a seguir mostra as propriedades Header
e Footer
, cada uma definida para um objeto Grid que contém um objeto Label:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.Header>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</ListView.Header>
<ListView.Footer>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Monkey"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</ListView.Footer>
...
</ListView>
A captura de tela a seguir mostra o cabeçalho resultante:
Exibir um modelo de cabeçalho e rodapé
As propriedades HeaderTemplate
e FooterTemplate
podem ser definidas como objetos DataTemplate usados para formatar o cabeçalho e o rodapé. Nesse cenário, as propriedades Header
e Footer
devem ser vinculadas à origem atual para que os modelos sejam aplicados, conforme mostrado no exemplo a seguir:
<ListView ItemsSource="{Binding Monkeys}"
Header="{Binding .}"
Footer="{Binding .}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Monkey"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</ListView.FooterTemplate>
...
</ListView>
Separadores de itens de controle
Por padrão, os separadores são exibidos entre os itens ListView no iOS e no Android. Esse comportamento pode ser alterado definindo a SeparatorVisibility
propriedade, do tipo SeparatorVisibility
, como None
:
<ListView ...
SeparatorVisibility="None" />
Além disso, quando o separador está habilitado, sua cor pode ser definida com a propriedade SeparatorColor
:
<ListView ...
SeparatorColor="Blue" />
Tamanho dos itens
Por padrão, todos os itens em ListView têm a mesma altura, que é derivada do conteúdo do DataTemplate que define a aparência de cada item. Entretanto, esse comportamento pode ser alterado com as propriedades HasUnevenRows
e RowHeight
. Por padrão, a propriedade HasUnevenRows
é false
.
A propriedade RowHeight
pode ser definida como int
que representa a altura de cada item em ListView, desde que HasUnevenRows
seja false
. Quando HasUnevenRows
é definida como true
, cada item em ListView pode ter uma altura diferente. A altura de cada item será derivada do conteúdo DataTemplate do item e, portanto, cada item será dimensionado de acordo com seu conteúdo.
Itens ListView individuais podem ser redimensionados programaticamente em tempo de execução, alterando as propriedades relacionadas ao layout dos elementos dentro do DataTemplate, desde que a propriedade HasUnevenRows
seja true
. O exemplo a seguir altera a altura de um objeto Image quando ele é tocado:
void OnImageTapped(object sender, EventArgs args)
{
Image image = sender as Image;
ViewCell viewCell = image.Parent.Parent as ViewCell;
if (image.HeightRequest < 250)
{
image.HeightRequest = image.Height + 100;
viewCell.ForceUpdateSize();
}
}
Nesse exemplo, o manipulador de eventos OnImageTapped
é executado em resposta a um objeto Image sendo tocado. O manipulador de eventos atualiza a altura do Image e o método Cell.ForceUpdateSize
atualiza o tamanho da célula, mesmo quando ela não está visível no momento.
Aviso
O uso excessivo do dimensionamento dinâmico de itens pode prejudicar o desempenho de ListView.
Layout da direita para a esquerda
ListView pode fazer o layout de seu conteúdo em uma direção de fluxo da direita para a esquerda, definindo sua propriedade FlowDirection
como RightToLeft
. Entretanto, o ideal é que a propriedade FlowDirection
seja definida em uma página ou layout raiz, o que faz com que todos os elementos da página ou layout raiz respondam à direção do fluxo:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ListViewDemos.RightToLeftListPage"
Title="Right to left list"
FlowDirection="RightToLeft">
<Grid Margin="20">
<ListView ItemsSource="{Binding Monkeys}">
...
</ListView>
</Grid>
</ContentPage>
O padrão FlowDirection
para um elemento com um pai é MatchParent
. Portanto, o ListView herda o valor da propriedade FlowDirection
do Grid, que por sua vez herda o valor da propriedade FlowDirection
do ContentPage.
Exibir dados agrupados
Grandes conjuntos de dados muitas vezes podem se tornar complicados quando apresentados em uma lista de rolagem contínua. Nesse cenário, organizar os dados em grupos pode melhorar a experiência do usuário, facilitando a navegação nos dados.
Os dados devem ser agrupados antes de serem exibidos. Isso pode ser feito criando uma lista de grupos, onde cada grupo é uma lista de itens. A lista de grupos deve ser uma coleção IEnumerable<T>
, onde T
define dois dados:
- Um nome de grupo.
- Uma coleção
IEnumerable
que define os itens pertencentes ao grupo.
O processo para agrupar dados, portanto, é:
- Crie um tipo que modele um único item.
- Crie um tipo que modele um único grupo de itens.
- Crie uma coleção
IEnumerable<T>
, ondeT
é o tipo que modela um único grupo de itens. Essa coleção é uma coleção de grupos, que armazena os dados agrupados. - Adicione dados à coleção
IEnumerable<T>
.
Exemplo
Ao agrupar dados, a primeira etapa é criar um tipo que modele um único item. O exemplo a seguir mostra a classe Animal
:
public class Animal
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}
A classe Animal
modela um único item. Um tipo que modela um grupo de itens pode então ser criado. O exemplo a seguir mostra a classe AnimalGroup
:
public class AnimalGroup : List<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, List<Animal> animals) : base(animals)
{
Name = name;
}
}
A classe AnimalGroup
herda da classe List<T>
e adiciona uma propriedade Name
que representa o nome do grupo.
Uma IEnumerable<T>
coleção de grupos pode então ser criada:
public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();
Esse código define uma coleção chamada Animals
, onde cada item da coleção é um objeto AnimalGroup
. Cada objeto AnimalGroup
compreende um nome e uma coleção List<Animal>
que define os objetos Animal
no grupo.
Os dados agrupados podem então ser adicionados à coleção Animals
:
Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
new Animal
{
Name = "American Black Bear",
Location = "North America",
Details = "Details about the bear go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
},
new Animal
{
Name = "Asian Black Bear",
Location = "Asia",
Details = "Details about the bear go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
},
// ...
}));
Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
new Animal
{
Name = "Baboon",
Location = "Africa & Asia",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
},
new Animal
{
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
},
new Animal
{
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
},
// ...
}));
Esse código cria dois grupos na coleção Animals
. O primeiro AnimalGroup
é nomeado Bears
e contém uma List<Animal>
coleção de detalhes do urso. O segundo AnimalGroup
é denominado Monkeys
e contém uma List<Animal>
coleção de detalhes do macaco.
ListView exibirá dados agrupados, desde que os dados tenham sido agrupados corretamente, definindo a propriedade IsGroupingEnabled
como true
:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Este é o código C# equivalente:
ListView listView = new ListView
{
IsGroupingEnabled = true
};
listView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
// ...
A aparência de cada item no ListView é definida definindo sua propriedade ItemTemplate
como um DataTemplate. Para obter mais informações, veja Definir a aparência do item.
A captura de tela a seguir mostra ListView exibindo dados agrupados:
Observação
Por padrão, ListView exibirá o nome do grupo no cabeçalho do grupo. Esse comportamento pode ser alterado personalizando o cabeçalho do grupo.
Personalize o cabeçalho do grupo
A aparência de cada cabeçalho de grupo pode ser personalizada definindo a propriedade ListView.GroupHeaderTemplate
como um DataTemplate:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"
BackgroundColor="LightGray"
FontSize="18"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
...
</ListView>
Nesse exemplo, cada cabeçalho de grupo é definido como um Label que exibe o nome do grupo e possui outras propriedades de aparência definidas. A captura de tela a seguir mostra o cabeçalho do grupo personalizado:
Importante
A propriedade GroupHeaderTemplate
é mutuamente exclusiva com a propriedade GroupDisplayBinding
. Portanto, ambas as propriedades não devem ser definidas.
Grupo sem modelos
ListView pode exibir dados agrupados corretamente sem definir a propriedade ItemTemplate
como um DataTemplate:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="true" />
Nesse cenário, dados significativos podem ser exibidos substituindo o método ToString
no tipo que modela um único item e no tipo que modela um único grupo de itens.
Controlar a rolagem
ListView define dois métodos ScrollTo
, que rolam os itens para visualização. Uma das sobrecargas rola o item especificado para exibição, enquanto a outra rola o item especificado no grupo especificado para exibição. Ambas as sobrecargas têm argumentos adicionais que permitem especificar a posição exata do item após a conclusão da rolagem e se a rolagem deve ser animada.
ListView define um evento ScrollToRequested
que é disparado quando um dos métodos ScrollTo
é invocado. O objeto ScrollToRequestedEventArgs
que acompanha o evento ScrollToRequested
possui muitas propriedades, incluindo ShouldAnimate
, Element, Mode
, e Position
. Algumas dessas propriedades são definidas a partir dos argumentos especificados nas chamadas do método ScrollTo
.
Além disso, ListView define um evento Scrolled
que é acionado para indicar que ocorreu rolagem. O objeto ScrolledEventArgs
que acompanha o evento Scrolled
possui propriedades ScrollX
e ScrollY
.
Detectar rolagem
ListView define um evento Scrolled
que é disparado para indicar que ocorreu rolagem. A classe ItemsViewScrolledEventArgs
, que representa o objeto que acompanha o evento Scrolled
, define as seguintes propriedades:
ScrollX
, do tipodouble
, representa a posição X da rolagemScrollY
, do tipodouble
, representa a posição Y da rolagem.
O exemplo XAML a seguir mostra um ListView que define um manipulador de eventos para o evento Scrolled
:
<ListView Scrolled="OnListViewScrolled">
...
</ListView>
Este é o código C# equivalente:
ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;
Nesse exemplo de código, o manipulador de eventos OnListViewScrolled
é executado quando o evento Scrolled
é acionado:
void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
// Custom logic
}
Importante
O evento Scrolled
é acionado para rolagens iniciadas pelo usuário e para rolagens programáticas.
Rolar um item para visualização
O método ScrollTo
rola o item especificado para visualização. Dado um objeto ListView chamado listView
, o exemplo a seguir mostra como rolar o item Macaco Probóscide para visualização:
MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;
Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, ScrollToPosition.MakeVisible, true);
Alternativamente, um item em dados agrupados pode ser visualizado especificando o item e o grupo. O exemplo a seguir mostra como exibir o item Macaco Probóscide no grupo Macacos:
GroupedAnimalsViewModel viewModel = BindingContext as GroupedAnimalsViewModel;
AnimalGroup group = viewModel.Animals.FirstOrDefault(a => a.Name == "Monkeys");
Animal monkey = group.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, group, ScrollToPosition.MakeVisible, true);
Observação
O evento ScrollToRequested
é acionado quando o método ScrollTo
é invocado.
Desabilitar animação de rolagem
Uma animação de rolagem é exibida ao rolar um item para visualização. No entanto, essa animação pode ser desabilitado definindo o argumento animated
do método ScrollTo
como false
:
listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: false);
Controlar a posição de rolagem
Ao rolar um item para visualização, a posição exata do item após a conclusão da rolagem pode ser especificada com o argumento position
dos métodos ScrollTo
. Esse argumento aceita um membro de enumeração ScrollToPosition
.
MakeVisible
O membro ScrollToPosition.MakeVisible
indica que o item deve ser rolado até ficar visível na visualização:
listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: true);
Iniciar
O membro ScrollToPosition.Start
indica que o item deve ser rolado até o início da visualização:
listView.ScrollTo(monkey, position: ScrollToPosition.Start, animate: true);
Center
O membro ScrollToPosition.Center
indica que o item deve ser rolado para o centro da visualização:
listView.ScrollTo(monkey, position: ScrollToPosition.Center, animate: true);
Término
O membro ScrollToPosition.End
indica que o item deve ser rolado até o final da visualização:
listView.ScrollTo(monkey, position: ScrollToPosition.End, animate: true);
Visibilidade da barra de rolagem
ListView define propriedades HorizontalScrollBarVisibility
e VerticalScrollBarVisibility
, que são apoiadas por propriedades vinculáveis. Essas propriedades obtêm ou definem um valor de enumeração ScrollBarVisibility
que representa quando a barra de rolagem horizontal ou vertical está visível. A enumeração ScrollBarVisibility
define os seguintes membros:
Default
indica o comportamento padrão da barra de rolagem para a plataforma e é o valor padrão para as propriedadesHorizontalScrollBarVisibility
eVerticalScrollBarVisibility
.Always
indica que as barras de rolagem ficarão visíveis, mesmo quando o conteúdo couber na visualização.Never
indica que as barras de rolagem não ficarão visíveis, mesmo que o conteúdo não caiba na visualização.
Adicionar menus de contexto
ListView suporta itens de menus de contexto, que são definidos como MenuItem objetos que ViewCell.ContextActions
são adicionados à * coleção no DataTemplate para cada item:
<ListView x:Name="listView"
ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Favorite"
Command="{Binding Source={x:Reference listView}, Path=BindingContext.FavoriteCommand}"
CommandParameter="{Binding}" />
<MenuItem Text="Delete"
Command="{Binding Source={x:Reference listView}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</ViewCell.ContextActions>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Os objetos MenuItem são revelados quando um item no ListView é clicado com o botão direito:
Para obter mais informações sobre itens de menu, consulte Exibir itens de menu.
Deslizar para atualizar
ListView oferece suporte à funcionalidade pull to refresh, que permite que os dados exibidos sejam atualizados puxando para baixo a lista de itens.
Para habilitar o pull para atualização, defina a propriedade IsPullToRefreshEnabled
como true
. Quando uma atualização é acionada, ListView gera o evento Refreshing
e a propriedade IsRefreshing
será definida como true
. O código necessário para atualizar o conteúdo do ListView deve então ser executado pelo manipulador do evento Refreshing
ou pela implementação ICommand que o RefreshCommand
executa. Depois que o ListView for atualizado, a propriedade IsRefreshing
deverá ser definida como false
, ou o método EndRefresh
deverá ser chamado no ListView, para indicar que a atualização foi concluída.
O exemplo a seguir mostra um ListView que usa pull para atualizar:
<ListView ItemsSource="{Binding Animals}"
IsPullToRefreshEnabled="true"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Nesse exemplo, quando o usuário inicia uma atualização, é executado o ICommand definido pela propriedade RefreshCommand
, que deve atualizar os itens que estão sendo exibidos. Uma visualização de atualização é mostrada enquanto a atualização ocorre, e consiste em um círculo de progresso animado. O valor da propriedade IsRefreshing
indica o estado atual da operação de atualização. Quando uma atualização é acionada, essa propriedade fará a transição automaticamente para true
. Assim que a atualização for concluída, você deverá redefinir a propriedade para false
.