Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Xamarin

Easy ListView With “Load more” in xamarin forms

0.00/5 (No votes)
6 Sep 2019CPOL1 min read 5.6K  
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)