Neste artigo irei demonstrar como você pode implementar uma lista com Infinite Scroll, dessa forma a sua lista será carregada “em partes”, com paginação e a quantidade de itens que você deseja por página. Esse tipo de carregamento é muito utilizado quando é necessário carregar uma lista com muitos elementos, evitando que o usuário espere toda a lista carregar para que possa selecionar o elemento desejado.
ADICIONANDO O NUGET PACKAGE
Clique com o botão direito em cima de sua Solution e selecione “Manage NuGet Packages for Solution…”.
No momento em que escrevo este artigo, o plugin utilizado encontra-se em prerelease, então para que possa encontra-lo, selecione a opção “Include prerelease”.
Digite “Xamarin.Forms.Extended.InfiniteScrolling” e selecione o plugin como demonstrado na imagem a seguir.
Selecione todos os projetos e clique no botão “Install”.
Service.cs
Está classe será necessária para simular uma requisição, observe que no método GetPessoasAsync está sendo utilizado um Delay de 3000 milissegundos.
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace InfiniteScrollDemo | |
{ | |
public class Service | |
{ | |
private readonly List<string> _pessoas = new List<string> | |
{ | |
"Adriano", "José", "Maria","Oscar", "João", "Eduarda", "Daniel", | |
"Suzana", "Paulo", "Pedro","Davi", "Felipe", "Fernanda", "Regina", "Nicole", | |
"Jesus", "Samira", "Samuel", "Elis", "Mayara", "Leticia", "Luiz", "Luciano", | |
"Neto", "Rodrigo", "Silvia", "Joel", "Vitória", "Fernando", "Samanta", "Karen", | |
"Marcio", "Cleusa", "Clara", "Luciana", "Cleber", "Jairo", "Jair", "Douglas", "Hamilton", | |
}; | |
public async Task<List<string>> GetPessoasAsync(int pageIndex, int pageSize) | |
{ | |
//Delay para simular o tempo de uma requisição | |
await Task.Delay(3000); | |
return _pessoas.Skip(pageIndex * pageSize).Take(pageSize).ToList(); | |
} | |
} | |
} |
MainViewModel.cs
Crie a classe MainViewModel, elá irá herdar de INotifyPropertyChanged e terá as seguintes propriedades:
- PageSize – Tamanho da página
- _isBusy – Indica quando começa(true) e quando termina(false) a requisição.
- Service – Objeto do tipo da classe Service criada anteriormente.
- Items – A lista com os elementos que serão apresentados.
using System.ComponentModel; | |
using System.Runtime.CompilerServices; | |
using System.Threading.Tasks; | |
using Xamarin.Forms.Extended; | |
namespace InfiniteScrollDemo | |
{ | |
public class MainViewModel : INotifyPropertyChanged | |
{ | |
private const int PageSize = 8; | |
private bool _isBusy; | |
readonly Service _service = new Service(); | |
public InfiniteScrollCollection<string> Items { get; } | |
} | |
} |
Download
Crie o método Download que será responsável em pegar a primeira página da lista.
private async Task Download() | |
{ | |
var items = await _service.GetPessoasAsync(pageIndex: 0, pageSize: PageSize); | |
Items.AddRange(items); | |
} |
OnPropertyChanged
Crie o método OnPropertyChanged que será responsável por notificar a cada modificação de propriedade.
public event PropertyChangedEventHandler PropertyChanged; | |
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) | |
{ | |
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | |
} |
Construtor
No construtor da classe instancie a lista, observe que OnLoadMore também busca os itens e adiciona na lista, pois ele será chamado a cada página carregada. No construtor adicione uma chamada para o método Download, ele será chamado para carregar apenas a primeira página.
public MainViewModel() | |
{ | |
Items = new InfiniteScrollCollection<string> | |
{ | |
OnLoadMore = async () => | |
{ | |
IsBusy = true; | |
// Ler a proxima pagina | |
var page = Items.Count / PageSize; | |
//Busca os itens | |
var items = await _service.GetPessoasAsync(page, PageSize); | |
IsBusy = false; | |
// Itens que serão adicionados | |
return items; | |
} | |
}; | |
Download(); | |
} | |
public bool IsBusy | |
{ | |
get => _isBusy; | |
set | |
{ | |
_isBusy = value; | |
OnPropertyChanged(); | |
} | |
} |
MainPage.xaml
Comece setando a MainViewModel no BindingContext, depois crie uma lista como você já deve estar acostumado.
Referencie o plugin Xamarin.Forms.Extended e sete o InfiniteScrollBehavior no ListView.Behaviors.
No footer da lista, adicione um ActivityIndicator que será apresentado enquanto a próxima página é carregada.
<?xml version="1.0" encoding="utf-8" ?> | |
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" | |
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | |
xmlns:local="clr-namespace:InfiniteScrollDemo" | |
xmlns:extended="clr-namespace:Xamarin.Forms.Extended;assembly=Xamarin.Forms.Extended.InfiniteScrolling" | |
x:Class="InfiniteScrollDemo.MainPage"> | |
<ContentPage.BindingContext> | |
<local:MainViewModel /> | |
</ContentPage.BindingContext> | |
<StackLayout> | |
<Label Text="Infinite Scroll" FontSize="40" HorizontalTextAlignment="Center" | |
TextColor="Black" Margin="0,30" /> | |
<ListView ItemsSource="{Binding Items}" | |
CachingStrategy="RecycleElement" | |
HasUnevenRows="True"> | |
<ListView.Behaviors> | |
<extended:InfiniteScrollBehavior IsLoadingMore="{Binding IsBusy}" /> | |
</ListView.Behaviors> | |
<ListView.ItemTemplate> | |
<DataTemplate> | |
<ViewCell> | |
<Grid Padding="12"> | |
<Label Text="{Binding .}" FontSize="30" TextColor="Black" /> | |
</Grid> | |
</ViewCell> | |
</DataTemplate> | |
</ListView.ItemTemplate> | |
<ListView.Footer> | |
<Grid Padding="6" IsVisible="{Binding IsBusy}"> | |
<Grid.Triggers> | |
<Trigger TargetType="Grid" Property="IsVisible" Value="False"> | |
<Setter Property="HeightRequest" Value="0" /> | |
</Trigger> | |
</Grid.Triggers> | |
<ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" | |
Color="#2196F3" VerticalOptions="Center" | |
HorizontalOptions="Center"/> | |
</Grid> | |
</ListView.Footer> | |
</ListView> | |
</StackLayout> | |
</ContentPage> |
Resultado
Esse e todos os exemplos deste blog encontram-se disponíveis no GitHub.
Muito bom!
CurtirCurtir
Muito bom Juliano ! Agora você poderia nos ensinar a fazer utilizando GroupCollection, tenho uma lista enorme dentro de outra lista, e estou apanhando para fazer… 😦
CurtirCurtir
Olá Michel,
Acho que este post pode te ajudar: https://julianocustodio.com/GroupedListView
Abraço.
CurtirCurtir
Fala juliano beleza… Então tenho uma lista dentro de outra lista, aí pelo que pesquisei deve-se montar um group collection, tentei mas não consegui carregar por demanda de forma correta, podia criar um artigo assim ?
CurtirCurtir
Olá Michel,
Acho que este post pode te ajudar: https://julianocustodio.com/GroupedListView
Abraço
CurtirCurtir
muito bom esse artigo, …. simples. uma duvida, como controlar qdo subir/voltar na lista ? tenho 10.000 itens.
CurtirCurtir
Olá…
Você pode substituir o uso da TableView e utilizar uma ListView, acredito que terá mais controle e muito mais opções de layout.
Espero ter ajudado.
CurtirCurtir