问题
i have a collectionview that i am trying to scroll programatically. the problem being that if the cell i want to scroll to is visible in the collection view it doesn't scroll it to the centre. so for the image below the lower cell is item 1. and it does not scroll to it but it will scroll past item 1 to item 2.
i have been trying to use UICollectionVieScrollPosition.CenterVertically but this does not seem to work.
self.collectionView?.scrollToItem(at: IndexPath(row: 1, section: 0), at: UICollectionViewScrollPosition.centeredVertically, animated: true)
is there a way around this to force the scrolling of cells that are visible to the centre of the collection?
回答1:
the best way i found to do this is to not use scrollToItem but to get the CGRect of the index and then make that visible.
let rect = self.collectionView.layoutAttributesForItem(at: IndexPath(row: 5, section: 0))?.frame
self.collectionView.scrollRectToVisible(rect!, animated: false)
回答2:
I'm trying to delay it with 0.1s. For my case, looks good for now:
collectionView.collectionViewLayout.invalidateLayout() //just in case, iOS10 may crash btw.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
Update:
ok, turns out that I'm using layout.estimatedItemSize
and autolayout
to calculate the width of my cells, that's why I have this problem.
That says, for me, it's because of CollectionView's dynamic sizing
.
After I back to calculate the width manually, everything works fine. (by using -collectionView:layout:sizeForItemAt:
)
回答3:
First of all you need to find the center of the CollectionView and this is how it can be done:
private func findCenterIndex() -> Int {
let center = self.view.convert(numberCollectionView.center, to: self.numberCollectionView)
let row = numberCollectionView!.indexPathForItem(at: center)?.row
guard let index = row else {
return 0
}
return index
}
then get the row number under your scrollToItem
and it should work:
collectionView.scrollToItem(at: IndexPath(item: findCenterIndex(), section: 0), at: .centeredVertically, animated: false)
call it from viewDidLayoutSubviews()
回答4:
If itemSize
is too small,scrollToItem
not working.
siwft
collectionView.contentOffset = offset
I use this fixed
回答5:
It seems that you have centred the first cell in your UICollectionView
vertically.
I have found that if I centred the first cell by adding an inset through the contentInset
property of UICollectionView
, its scrollToItem(at:at:animated:)
method also doesn't work for cells already visible.
However, if I centred the first cell by adding an inset through the sectionInset
property of UICollectionViewFlowLayout
, then scrollToItem(at:at:animated:)
works for visible cells.
Specifically, in code:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Padding needed to allow the first and last cells to be centred vertically.
let insectHeight = (collectionView.bounds.height - collectionViewFlowLayout.itemSize.height) / 2.0
// This way is disabled because scrollToItem doesn't work for visible cells.
// collectionView.contentInset = UIEdgeInsets(top: insectHeight,
// left: 0,
// bottom: insectHeight,
// right: 0)
// This is the way for scrollToItem to work for visible cells.
collectionViewFlowLayout.sectionInset = UIEdgeInsets(top: insectHeight,
left: 0,
bottom: insectHeight,
right: 0)
}
My guess is that contentInset
is a property UICollectionView
inherited from UIScrollView
, and the way scrollToItem(at:at:animated:)
works out the offset seems incompatible to the way contentInset
is used by UIScrollView
.
来源:https://stackoverflow.com/questions/41413240/uicollectionviewscrollposition-not-working