Corrado's Blog 2.0

Online thoughts of a technology funatic

Xamarin: Infinite scrolling list in iOS app

I’ve spend the last few weeks studying Xamarin, not because I’m considering abandoning the Windows platform but because I think it’s clear that, as developer, we need to take note that there are other big platforms with which it is right to live with.

While not yet mature and in some cases quite cumbersome, my experience with it was highly positive and I absolutely recommend it in case you need to create Android and/or iOS applications.

This post comes from a need I had during development of a iOS application: Create an infinite scrolling list of data starting from paged data coming from a REST service.

Note: I’m a Xamarin beginner so this might not be the perfect solution, but it worked fine in my case.

To get infinite scrolling I created a custom UITableSource

public class BookedCarsTableViewSource : UITableViewSource
    {
        private readonly DataService dataService;
        private readonly PagedResult<BookedCarResponse> firstPage;
        private readonly List<BookedCarResponse> bookedCars;
        private int pageIndex;
        private bool isFetching;

        private const string cellId = "bookedCarCell";

        public BookedCarsTableViewSource(DataService dataService, PagedResult<BookedCarResponse> firstPage)
        {
            this.dataService = dataService;
            this.firstPage = firstPage;
            this.bookedCars = firstPage.Result.ToList();
            this.pageIndex = 0;
        }

        public override int RowsInSection(UITableView tableview, int section)
        {
            return (int)Math.Max(this.bookedCars.Count, this.firstPage.TotalCount);
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            int index = indexPath.Row;
            UITableViewCell cell = tableView.DequeueReusableCell(cellId) ?? new UITableViewCell(UITableViewCellStyle.Subtitle, cellId);
            BookedCarResponse bookedCar = this.bookedCars[index];
            cell.TextLabel.Text = bookedCar.CarPlate;
            cell.DetailTextLabel.Text = bookedCar.CompanyName;            
            if (!this.isFetching && this.pageIndex < this.firstPage.TotalPages && index > this.bookedCars.Count * 0.8)
            {
                this.isFetching = true;
                Task.Factory.StartNew(this.LoadMore);
            }

            return cell;
        }

        private async void LoadMore()
        {
            this.pageIndex++;
            var nextPage = await this.dataService.GetBookedCars(this.pageIndex, this.firstPage.PageSize);
            this.bookedCars.AddRange(nextPage.Result);
            this.isFetching = false;
        }
    }

As you see the trick is inside GetCell, when requested index is near the end of currently available items I spin a new request and add results to bookedCars collection.

In order to get initial block of items I used this code inside related controller:

public class BookedCarsScreenController : UITableViewController
    {
        private PagedResult<BookedCarResponse> firstPage;

        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            this.firstPage = await DataManager.Current.GetBookedCars(0, 30);
            this.TableView.Source = new BookedCarsTableViewSource(DataManager.Current, firstPage);
            this.TableView.ReloadData();
        }
    }

I had to invoke TableView’s ReloadData otherwise list was appearing initially empty.

Note that since I’m using Subtitle layout I didn’t find the way to use  iOS 6 automatic cell reuse mode.

Hope it helps! Smile

6 Responses to “Xamarin: Infinite scrolling list in iOS app”

  1. I am calling this code, and it fetches the second page in my tabledata source, however It never starts to paint rows 11-20. I am getting 10 at a time.

    I get the first ten, it does the Add Range for the next 10, but the table never keeps going to paint the next cells. What is the trick with that?

    Otherwise this works perfectly for me. I appreciate you sharing this!

    Comment by Dale Bingham — 04/08/2014 @ 01:55

  2. Hi, honestly no idea it works fine for me, have you tried invoking Reload data?

    Comment by corcav — 04/09/2014 @ 08:52

  3. I have read your post but I don’t understand. Do you have github link?

    Comment by Minh thang — 06/06/2015 @ 13:41

  4. Hello Corrado. If you add MVVMCross to the solution you can achieve infinite scrolling for iOS, Android and Windows, sharing much of the code base. I’ve written about it here if you want to take a look.

    http://www.sequence.co.uk/blog/infinite-scrolling-using-mvvmcross-and-xamarin/

    Best regards
    Howard

    Comment by Howard Bayliss — 08/10/2015 @ 09:39

  5. The reason folks can’t get this to work is because you have to do the following after you update the list that your table source uses:

    InvokeOnMainThread(() => _uiTableView.ReloadData());

    _uiTableView gets passed into the GetCell method so inside the LoadMore, right after you call AddRange, insert the line above. You will have to have a handle on the _uiTableView to do this.

    Comment by Perry — 19/03/2016 @ 18:21

  6. Aw, this was a really good post. Taking a few minutes and
    actual effort to create a very good article… but what can I say… I hesitate a whole lot and
    never manage to get nearly anything done.

    Comment by m88 — 28/03/2016 @ 14:08

RSS feed for comments on this post. TrackBack URL

Leave a Response