65.9K
CodeProject is changing. Read more.
Home

Easy ListView With “Load more” in xamarin forms

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1 vote)

Aug 26, 2019

CPOL

1 min read

viewsIcon

5623

With the increased amount of data a lazy loading mechanism is required in this article, we will explain how to build a lazy loaded list view easily.

Modern mobile applications are mostly data driven apps that depend heavily on listview’s. With the increased amount of data a lazy loading mechanism is required in this article, we will explain how to build a lazy loaded list view easily.

As an example I will build a last fm app that return a list of albums for an artist.

I started by creating a new xamarin app and then install the following nuget packages

  1. Inflatable.Lastfm
  2. Syncfusion.Xamarin.SfListView
  3. AsyncEnumerableExtensions.Standard

Now let's create our view model

public class MainPageViewModel
    {
        private LastfmClient _client;
        
public MainPageViewModel()
        {
            _client = new LastfmClient("b471c30029ba983849723e5120e7504c", "24c4739698eebb92f792b118095dbdff");
            Artists = GetArtists().ToStandardIIncrementelLoadingCollection(10);
        }
        
public IIncrementelLoadingCollection<AlbumModel> Artists { get; }

private IAsyncEnumerable<AlbumModel> GetArtists()
        {
            return AsyncEnumerableBuilder.FromPaged((i, i1) =>
                    _client.Artist.GetTopTracksAsync("Britney Spears", true, i, i1), 
                tracks => tracks.Select(t =>
                    new AlbumModel()
                    {
                        Name = t.Name,
                        Id = t.Id,
                        Image = t.Images.Large.ToString(),
                        Duration = t.Duration
                    }), 
                (i, tracks) => tracks.TotalItems > i,
                (tracks, i) => tracks.Count() + i,
                tracks =>
                {
                    var pagenumber = (tracks?.Page ?? 0) + 1;
                    return pagenumber;
                },
                tracks => 20);
        }
    }
}

The method AsyncEnumerableBuilder.FromPaged was described in detail in my previous article "Mobile paged requests using IAsyncEnumerable" as a fast summary it allow building an IAsyncEnumerable from a method that return paged results which is "GetTopTracksAsync" in our case .

The method ToStandardIIncrementelLoadingCollection allow the conversation from IAsyncEnumerable to a bindable incremental collection that expose this interface

public interface IIncrementelLoadingCollection<T> : ICollection<T>, IEnumerable<T>, IEnumerable
  {
    ICommand LoadMoreCommand { get; }
         bool IsBusy { get; }
  }

The integer parameter is the number of items that will get loaded every time the user tap on load more , in our example it is 10 "ToStandardIIncrementelLoadingCollection(10)"

Now finally the view

<StackLayout BindingContext="{Binding Path=Artists}">
        <xForms:SfListView x:Name="listView" 
                               ItemSpacing="10" 
                               LoadMoreOption="Manual"
                               LoadMoreCommand="{Binding LoadMoreCommand }"
                               IsBusy="{Binding IsBusy}"
                               ItemsSource="{Binding }">
            <xForms:SfListView.ItemTemplate>
                <DataTemplate>
                <ViewCell>
                        <StackLayout Orientation="Horizontal" Spacing="10">
                            <Image Source="{Binding Image}" HeightRequest="100" WidthRequest="100" />
                            <Label Text="{Binding Name}" />
                        </StackLayout>
                        </ViewCell>
                   
                </DataTemplate>
            </xForms:SfListView.ItemTemplate>
            <xForms:SfListView.LoadMoreTemplate>
                <DataTemplate>
                    <Grid>
                        <Label Text="Load More Items" TextColor="Black" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" IsVisible="{Binding IsBusy, Converter={StaticResource inverseBoolConverter}, Source={x:Reference Name=listView}}" />
                        <xForms:LoadMoreIndicator IsRunning="{Binding IsBusy, Source={x:Reference Name=listView}}" IsVisible="{Binding IsBusy, Source={x:Reference Name=listView}}" Color="Red" VerticalOptions="Center"/>
                    </Grid>
                </DataTemplate>
            </xForms:SfListView.LoadMoreTemplate>
        </xForms:SfListView>
    </StackLayout>

The core part is

<StackLayout BindingContext="{Binding Path=Artists}">
<xForms:SfListView x:Name="listView" 
                               ItemSpacing="10" 
                               LoadMoreOption="Manual"
                               LoadMoreCommand="{Binding LoadMoreCommand }"
                               IsBusy="{Binding IsBusy}"
                               ItemsSource="{Binding }">

we set the binding context of the listview to Artists which is our IIncrementelLoadingCollection , the LoadMoreCommand to the Artist.LoadMoreCommand and IsBusy to Artist.IsBusy and finally the data source to the Artists itself.