In my setup I have a horizontal collection view with chip style, on initial load the first chip is selected by default and corresponding to the chip an API call is made and it's data is loaded into a vertical UICollectionView right below.
On tapping any of the chips in the UICollectionView an API call is initiated and the selected cell is scrolled into the centre of collectionview using scrollToItem(at: selectedChipIndexPath, at: .centerHorizontally , animated: true). Plus I have to reload the the last selected & current selected indexPath to indicate that new cell is selected.
Everything works fine if user taps on the chips, looks at the below loaded data and then taps on the next chip.
But if the user taps on consecutive chips quickly then scrollToItem(at: selectedChipIndexPath, at: .centerHorizontally , animated: true) glitches the scroll animation some times causing an unpleasant UX experience.
Here is my code:
horizontalCollectionView.reloadItems(at: [lastSelectedIndexPath, selectedChipIndexPath])
// API Call
/*
This is an async call, which ones finishes informs the ViewController to the update it's vertical collection view with new data
*/
viewModel.fetchProductData(forPositon: selectedChipIndexPath)
DispatchQueue.main. asyncAfter ( .now() + .seconds(0.4)) {
horizontalCollectionView.scrollToItem(at: selectedChipIndexPath, at: .centerHorizontally , animated: true)
}
If I don't delay the scrolling by few milliseconds then scroll animation of collection view starts to glitch very badly.
So can anyone point me in the right direction on how can I handle or queue up multiple scrollToItem(at:at:animated:) calls so that my collectionView scroll animation doesn't glitch.
I did try to wrap scrollToItem(at:at:animated:) in batch updates but it didn't work.
Update 1:
Here's how my UI looks mostly
Horizontal Collection View : For Product Categories
Vertical Collection View : For Products themselves
Update 2:
The solution provided by DonMag works but it introduces another problem, according to my designs I have to change the font type from regular to bold for the UILabel inside the chips when selected, doing this causes the label frame size to increase and for most text the label gets clipped since I am just manipulating the views instead of reloading the cells themselves.
I tried to invalidate the CollectionView Flow Layout. But it again brought me to the same problem of the scrolling glitch.

Without seeing your full code, the issue is likely being caused by your repeated calls to
.reloadItems(...)If you are doing that only to change the appearance of the selected cell, it is unnecessary.
Instead, let the collection view track the selected cell (as it does by default), and have your cell modify its own appearance based on its selected state.
For example - if we create a cell with a single label in a typical manner like this:
We've overridden
var isSelected: Bool... the collection view will set that property when needed, and now our cell updates its "selected / un-selected" appearance automatically.No need to call
.reloadItemsExample view controller with horizontal collection view using the above cell - note that I'm creating 4 "repeating sets" of the sample tags (prefixed by 1-4), so we have plenty of cells to scroll:
Edit - additional requirement: cell font change to bold when selected, without causing cell size change...
The easiest way to do that is to add two labels to the cell - one with Bold font, the other with Regular font.
Setup the constraints so the Bold label will control the width and the Regular label will be slightly wider than necessary.
Show the Bold label when selected, show the Regular when not.
So, slightly modified cell class from above:
Then in the controller's
cellForItemAt, instead of setting the text of the "single" label, we'll set the cell'stitleproperty, which will set the same text in both labels:Edit 2 - responding to comment about selecting programmatically...
First, do NOT call:
That does not tell the collection view that the cell has been selected.
This is the proper way to programmatically select a cell (in this case, we want to select cell/item
5and have it scroll to the center):Note that programmatically selecting the cell will NOT call the
didSelectItemAtdelegate func. That is called to let you know that the user selected a cell.So, if you want to programmatically select a cell, and you want something to happen, follow it up with that "do something" code.
For example: