Monday January 28th, 2019

Xamarin Forms Lazy Loading(Infinite Scroll)

By Ebubekir Sezer

When we are making an app, we add some features to make application have better design. One of the feature is that Lazy Loading. Lazy loading works like, When we have a list view and we have specific number item, we scroll the screen and then other items appear in that specific number.

I made a simple application to show how to use lazy loading. In this application, There are information about the football players, Their names, pictures and teams. I created a class and initialize the variables that i use. Then i created a list and then i sent the data to that list, later i created a function like that;

 public async Task<List<Player>> GetItemAsync(int pageIndex,int pagesize)
        {
            await Task.Delay(2000);
            return players.Skip(pageIndex * pagesize).Take(pagesize).ToList();
        }

Thanks to this function, i make the how many items will be in the page. I added the Xamarin.Forms.Extended.InfiniteScrolling nuget package to the my application. Later, I created a class model to make binding process and i inherited this class from the INotifyPropertyChanged interface. I wrote these codes to the class;

private bool _isBusy;
        private const int PageSize = 10;
        readonly DataService dataService = new DataService();

        public event PropertyChangedEventHandler PropertyChanged;

        public InfiniteScrollCollection<Player> Players { get; set; }
            
        public bool IsBusy
        {
            get => _isBusy;
            set
            {
                _isBusy = value;
                OnPropertyChanged();
            }
        }
        public MainViewModel()
        {
            Players = new InfiniteScrollCollection<Player>
            {
                OnLoadMore = async () =>
                 {
                     IsBusy = true;
                     var page = Players.Count / PageSize;
                     var player = await dataService.GetItemAsync(page, PageSize);
                     IsBusy = false;
                     return player;
                 },
                OnCanLoadMore = () =>
                {
                    return Players.Count < 50;
                }
            };
            DownloadDataAsync();
        }
        private async Task DownloadDataAsync()
        {
            var items = await dataService.GetItemAsync(pageIndex: 0, pagesize: PageSize);
            Players.AddRange(items);
        }
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyname=null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }

From this codes, I used boolean isBusy which is controlled the user action. Also i determine number of the items in the page which is 10. Then i created an object from my data service and also i created an from InfiniteScrollCollection<Player> Players. Later i wrotes some functions that controlled process of the lazy loading in the class. I also make a really simple design for the application.

<ContentPage.BindingContext>
        <local:MainViewModel/>
    </ContentPage.BindingContext>
    <StackLayout>
        <Label Text="PLAYERS"
               TextColor="Black"
               FontSize="Large"
               VerticalOptions="Center"
               HorizontalOptions="Center"/>
        <ListView ItemsSource="{Binding Players}"
                  CachingStrategy="RecycleElement"
                  HasUnevenRows="True">
            <ListView.Behaviors>
                <extended:InfiniteScrollBehavior IsLoadingMore="{Binding IsBusy}"/>
            </ListView.Behaviors>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Padding="10,10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="0.4*"/>
                                <ColumnDefinition Width="0.6*"/>
                            </Grid.ColumnDefinitions>
                            <Image Source="{Binding Image}"
                                   Grid.Column="0"
                               VerticalOptions="Center"
                               HorizontalOptions="StartAndExpand"
                                   WidthRequest="100"
                                   HeightRequest="100"
                               Aspect="AspectFit"/>
                            <Grid Grid.Column="1" VerticalOptions="Center" HorizontalOptions="Start">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="0.7*"/>
                                    <RowDefinition Height="0.3*"/>
                                </Grid.RowDefinitions>
                                <Label Text="{Binding Name}"
                                   Grid.Row="0"
                                       VerticalOptions="Center"
                                       HorizontalOptions="Start"
                               FontSize="Medium"
                               TextColor="Black"/>
                                <Label Text="{Binding Club}"
                                       Grid.Row="1"
                                       FontSize="Small"
                                       TextColor="Black"
                                       VerticalOptions="Start"
                                       HorizontalOptions="Start"/>
                            </Grid>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.Footer>
                <Grid IsVisible="{Binding IsBusy}">
                    <Grid.Triggers>
                        <Trigger TargetType="Grid"
                                 Property="IsVisible"
                                 Value="False">
                            <Setter Property="HeightRequest"
                                    Value="0"/>
                        </Trigger>
                    </Grid.Triggers>
                    <Label Text="Loading..."
                           TextColor="Green"
                           VerticalOptions="Center"
                           HorizontalOptions="Center"
                           FontAttributes="Bold"
                           FontSize="Medium"/>
                </Grid>
            </ListView.Footer>
        </ListView>
    </StackLayout>

Here is the view of the application;