Forum Xamarin.iOS
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

UITableView Infinite Scrolling for Pagination

MichaelMulhausenMichaelMulhausen USUniversity ✭✭

I'm looking to implement what seems like a fairly common mechanic: pagination using infinite scrolling in a UITableView,. But I haven't found a solid example on how to do so. I'm wondering if there's a straight forward approach in implementing something like this. Any examples would be greatly appreciated. Thanks!

Posts

  • STRSTR THMember

    I 'll try to do follow from this blog http://codeworks.it/blog/?p=182
    but it display only first page , not reloaddata
    my code adapted to

    public class ItemsListDataSource: UITableViewSource
    {

        private readonly ProductServiceService prodService;
        private readonly ListItemCollection<ListItemValue> firstPage;
        private readonly List<ListItemValue> allItems;
        private int pageIndex;
        private bool isFetching;
    
        int totalRowByPage = 30;
        int PageSize = 30;
        private const string cellId = "prodCell";
    
    
        public ItemsListDataSource (ProductServiceService dataService, ListItemCollection<ListItemValue> firstPage,int page)
        {
            this.prodService = dataService;
            this.firstPage = firstPage;
            this.allItems = firstPage.ToList();
            this.pageIndex = page;
        }
    
        #region implemented abstract members of UITableViewSource
    
        public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            int index = indexPath.Row;
            UITableViewCell cell = tableView.DequeueReusableCell(cellId) ?? new UITableViewCell(UITableViewCellStyle.Subtitle, cellId);
            ListItemValue prod = this.allItems[index];
            cell.TextLabel.Text = prod.Name;
            cell.DetailTextLabel.Text = prod.Code;          
    
            if (!this.isFetching && totalRowByPage == PageSize && index > this.allItems.Count * 0.8)
            {
                this.isFetching = true;
                Task.Factory.StartNew(this.LoadMore);
            }
    
            return cell;
        }
    
        public override nint RowsInSection (UITableView tableview, nint section)
        {
            return (int)Math.Max(this.allItems.Count, this.firstPage.Count);
        }
    
    
        private  void LoadMore()
        {
            this.pageIndex++;
    
            var nextPage =  clsUtils.getAllProducts(pageIndex, PageSize,  "N");
            totalRowByPage = nextPage != null ? nextPage.Count : 0;
            this.allItems.AddRange(nextPage);
            this.isFetching = false;
        }       
        #endregion
    }
    

    //////////
    public class ItemsListViewController: UITableViewController
    {

        private ListItemCollection<ListItemValue> firstPage;
    
    
        public ItemsListViewController () : base (UITableViewStyle.Grouped)
        {
            //TableView.RegisterClassForCellReuse (typeof(ItemsDataListControllerCell), MyCellId);
    
        }
        public override  void ViewDidLoad()
        {
            base.ViewDidLoad();
            this.firstPage =  clsUtils.getAllProducts(1, 30,"N");// call data from web service
            ProdService.ProductServiceService prodService = clsUtils.getProductService ();
            this.TableView.Source = new ItemsListDataSource (prodService, firstPage, 1);
            this.TableView.ReloadData();
        }
    
    
    
    
    
        public override void DidReceiveMemoryWarning ()
        {
            // Releases the view if it doesn't have a superview.
            base.DidReceiveMemoryWarning ();
    
            // Release any cached data, images, etc that aren't in use.
        }
    
        public override void ViewDidAppear (bool animated)
        {
            base.ViewDidAppear (animated);
    
            //
            // Deselect all cells when appearing
            //
            var sel = TableView.IndexPathForSelectedRow;
            if (sel != null) {
                TableView.DeselectRow (sel, true);
            }
        }
    
    
    }
    
  • PerryPerry USMember ✭✭
    _lMerchantsList.AddRange(_mMerchants.MerchantList);
    InvokeOnMainThread(() => _uiTableView.ReloadData());
    

    I got that sample working but it was missing a critical piece. After you update the list your table source is using, in this case _lMerchantsList, you have call ReloadData on the UITableView that is passed into the GetCell method. Additionally you have to invoke that on the main thread. The second line I post above is the missing link. Not sure how the sample was even working.

  • DougEFreshDougEFresh USMember ✭✭

    @Perry, but where do you put this Invoke? If you put it in the async call you can't access ReloadData() because you are in UITableViewSource not the controller?
    I'm new to mobile apps and Xamarin so maybe I'm missing something simple?

  • PerryPerry USMember ✭✭
    edited March 2016

    You will notice the GetCell override in your table source class takes a UITableView. That is the UITableView from your controller. So, set a private variable on your table source like so:

    private UITableView _uiTableView;

    Then in GetCell, do this:

    _uiTableView = tableView;

    You now have a handle on the table view from your controller.

    So, in LoadData, you can now do this:

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

    Hope that helps.

    EDIT: or pass in a reference to the table view to your table source

  • DougEFreshDougEFresh USMember ✭✭

    Thanks! I see now, makes total sense. I guess I didn't realize that the UITableView was part of the override, just glazed right over it. I was looking at passing a reference from the controller but it felt like there had to be a more elegant way to do it.

    Now I just need to add in a nice little spinning "loading" notice.

    thanks again. cheers.

Sign In or Register to comment.