Lazy Loading Data in iOS Carplay
Asked Answered
M

3

4

How to lazy load the items while the user scrolling in Carplay ?

I am using beginLoadingChildItems from MPPlayableContentDataSource to load the first set of items but how I can call the next page when a user scrolls to the bottom of the page?

enter image description here

Metaphosphate answered 27/12, 2019 at 14:8 Comment(2)
I am facing one more problem here - playableContentManager?.reloadData() never works. When I am adding items to the list & calling this function nothing happens.Metaphosphate
follow this github.com/pronebird/UIScrollView-InfiniteScrollAce
B
5

The way you can achieve this is inside the following function:

func beginLoadingChildItems(at indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void)

As Example:

if (indexPath[componentIndex] + 1) % Threshold == 0 { // Threshold is Your Defined Batch Size

    // Load the next corresponding batch 

}

Load your lazy data, then call:

completionHandler(nil) // In case of no error has occurred

,but firstly, you need to return the total items count correctly in the following function:

func numberOfChildItems(at indexPath: IndexPath) -> Int

Something like the below,

class YourDataSource : MPPlayableContentDataSource {

    private var items = [MPContentItem]()
    private var currentBatch = 0

    func beginLoadingChildItems(at indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void) {

        // indexPath[1]: is current list level, as per CarPlay list indexing (It's an array of the indices as ex: indexPath = [0,1] means Index 0 in the first level and index 1 at the second level).
        // % 8: Means each 8 items, I will perform the corresponding action.
       // currentBatch + 1 == nextBatch, This check in order to ensure that you load the batches in their sequences.

        let currentCount = indexPath[1] + 1

        let nextBatch = (currentCount / 8) + 1

        if currentCount % 8 == 0 && currentBatch + 1 == nextBatch { 

            // Load the next corresponding batch 
            YourAPIHandler.asyncCall { newItems in

                self.currentBatch = self.currentBatch + 1

                items.append(newItems)

                completionHandler(nil)

                MPPlayableContentManager.shared().reloadData()

            }

        } else {

            completionHandler(nil)

        }


    }

}

func numberOfChildItems(at indexPath: IndexPath) -> Int {

    return self.items.count

}
Brio answered 7/1, 2020 at 23:48 Comment(5)
Hi, Thank you for your reply. Can you please tell what should I return total number of items as there can be infinite items and what is componentIndex in indexPath[componentIndex]? Please replyMetaphosphate
I want to load 8 items in single page & when user scrolls to last item load next 8 itemsMetaphosphate
Can you check the updated answer, I have tried to add an example for illustration.Brio
Thank you for your answer, in my code issue was, last item in the list we have to declare as a container, then only beginLoadingChildItems delegate gets called. That was missing in my code.Metaphosphate
Best of Luck 👍Brio
S
2

CarPlay does not support infinite scrolling by default. There is no callback when the last item on the list is displayed. However, the solution by @amr-el-sayed is an interesting one, since CarPlay will preload categories when they first appear on the screen. Thus, if the last item on the list is a category, CarPlay will call beginLoadingChildItemsAtIndexPath with the indexpath of the last item on the list, which could be used to simulate infinite scrolling. In that case, it becomes necessary to call MPPlayableContentManager reloadData because the preload is actually being called for the nested category (which is not displayed), rather than the category for which you are trying to implement infinite scrolling. This can result in some flash, as CarPlay must now redraw the entire UI. If possible, a better solution is simply to load a long list of items initially. Note that CarPlay will enforce a limit of enforcedContentItemsCount when MPPlayableContentManager.contentLimitsEnforced is true, for example, when a vehicle is in motion.

Squall answered 24/1, 2020 at 13:9 Comment(0)
M
0

Key here is to declare your MPContentItem as a container like this

            let item = MPContentItem(identifier: "Tab \(indexPath)")
            item.isContainer = true
            item.isPlayable = false
            return item

Then only the framework will call beginLoadingChildItems method when that item is visible on the screen.

Inside beginLoadingChildItems call the load more function and refresh the items using

playableContentManager?.reloadData()

function

Metaphosphate answered 12/1, 2020 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.