ListView

Procurar amostra. Procurar no exemplo

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 tipo IEnumerable, especifica a coleção de itens a serem exibidos e tem um valor padrão de null.
  • 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 tipo object, 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 o Footer.
  • 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 propriedade GroupDisplayBinding. Portanto, definir essa propriedade definirá GroupDisplayBinding como null.
  • HasUnevenRows, do tipo bool, indica se os itens da lista podem ter linhas de alturas diferentes. O valor padrão dessa propriedade é false.
  • Header, do tipo object, 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 o Header.
  • HorizontalScrollBarVisibility, do tipo ScrollBarVisibility, indica quando a barra de rolagem horizontal ficará visível.
  • IsGroupingEnabled, do tipo bool, indica se os dados subjacentes devem ser exibidos em grupos. O valor padrão dessa propriedade é false.
  • IsPullToRefreshEnabled, do tipo bool, 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 tipo bool, 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 tipo int, determina a altura de cada linha quando HasUnevenRows é false.
  • SelectedItem, do tipo object, representa o item atualmente selecionado noListView.
  • SelectionMode, do tipo ListViewSelectionMode, 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 tipo SeparatorVisibility, define se os separadores são visíveis entre os itens.
  • VerticalScrollBarVisibility, do tipo ScrollBarVisibility, 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 tipo BindingBase, a ligação a ser usada para exibir o cabeçalho do grupo. Essa propriedade é mutuamente exclusiva com a propriedade GroupHeaderTemplate. Portanto, definir essa propriedade definirá GroupHeaderTemplate como null.
  • GroupShortNameBinding, do tipo BindingBase, a ligação do nome a ser exibido em listas de atalhos agrupadas.
  • CachingStrategy, do tipo ListViewCachingStrategy, 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 objeto ItemVisibilityEventArgs que acompanha esse evento define as propriedades Item e Index.
  • ItemDisappearing, que é gerado quando a representação visual de um item está sendo removida do layout visual do ListView. O objeto ItemVisibilityEventArgs que acompanha esse evento define as propriedades Item e Index.
  • ItemSelected, que é gerado quando um novo item na lista é selecionado. O objeto SelectedItemChangedEventArgs que acompanha esse evento define as propriedades SelectedItem e SelectedItemIndex.
  • ItemTapped, que surge quando um item no ListView é tocado. O objeto ItemTappedEventArgs que acompanha esse evento define as propriedades Group, Item, e ItemIndex.
  • Refreshing, que é gerado quando uma operação pull to refresh é acionada no ListView.
  • Scrolled, . O objeto ScrolledEventArgs que acompanha esse evento define as propriedades ScrollX e ScrollY.
  • ScrollToRequested . O objeto ScrollToRequestedEventArgs que acompanha esse evento define as propriedades Element, Mode, Position, ScrollX, ScrollY e ShouldAnimate.

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:

Captura de tela do ListView onde cada item é modelado.

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 tipo string, define o texto primário a ser exibido.
  • TextColor, do tipo Color, representa a cor do texto primário.
  • Detail, do tipo string, 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 tipo object, 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:

Captura de tela do ListView onde cada item é um TextCell.

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:

Captura de tela do ListView onde cada item é um ImageCell.

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:

Captura de tela do ListView onde cada item é modelado com um ViewCell.

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:

Captura de tela da seleção do modelo de item de tempo de execução do ListView.

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:

Captura de tela de um ListView com uma seleção.

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, como RecycleElement 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 tipo object, 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 o Header.
  • Footer, do tipo object, 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 o Footer.

Essas propriedades são apoiadas por objetos BindableProperty, o que significa que as propriedades podem ser alvos de vinculações de dados.

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:

Captura de tela de um cabeçalho de string ListView.

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:

Captura de tela do cabeçalho e rodapé do CollectionView usando visualizações.

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>, onde T é 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:

Captura de tela de dados agrupados em um ListView.

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:

Captura de tela de um cabeçalho de grupo personalizado em um ListView.

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 tipo double, representa a posição X da rolagem
  • ScrollY, do tipo double, 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 propriedades HorizontalScrollBarVisibility e VerticalScrollBarVisibility.
  • 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:

Captura de tela dos itens do menu de contexto do CollectionView.

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.