I have a UICollectionView
that has 20 cells and 1 section. I made each cell 320 in width and 304 in height.
I scroll the collection view programmatically using two buttons at the bottom of the collection view using scrollToItemAtIndexPath(currentIndex + 1)
. I only scroll them 1 by 1.
This works fine in iPhone 4s and iPhone 5/5s. The problem appears when using an iPhone 6/6 Plus.
When I scrollToItemAtIndexPath
it scrolls 2 cells at a time.
How can I prevent this from happening? I tried to make the cell fit the width of the screen but just one cell appeared, and the rest of the UICollectionView
was black.
EDIT:
Here is the datasource code:
extension ViewController: UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 32
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("collectionCell", forIndexPath: indexPath) as! CollectionCell
cell.backgroundColor = UIColor.whiteColor()
self.current = indexPath
self.configureCell(cell, atIndexPath: indexPath) as! CollectionCell
return cell
}
func configureCell(cell: CollectionCell, atIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let string = textArray[indexPath.item % 20] as String
cell.textView.text = string
cell.textView.backgroundColor = UIColor.cloudsColor()
return cell
}
}
And here is how I scroll them:
func buttonSelected(sender: UIButton) {
switch sender.tag {
case 0:
let previousItem: NSIndexPath = NSIndexPath(forItem: self.current.item - 1, inSection: self.current.section)
self.collectionView?.scrollToItemAtIndexPath(previousItem, atScrollPosition:UICollectionViewScrollPosition.CenteredHorizontally, animated:true)
case 1:
let nextItem: NSIndexPath = NSIndexPath(forItem: self.current.item + 1, inSection: self.current.section)
self.collectionView?.scrollToItemAtIndexPath(nextItem, atScrollPosition:UICollectionViewScrollPosition.CenteredHorizontally, animated:true)
default: break
}
}
I've solved this using a custom FlowLayout in the collection view. Here it is:
class CenterFlowLayout: UICollectionViewFlowLayout {
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
if let cv = self.collectionView {
let cvBounds = cv.bounds
let halfWidth = cvBounds.size.width * 0.5
let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidth
if let attributesForVisibleCells = self.layoutAttributesForElementsInRect(cvBounds) as [UICollectionViewLayoutAttributes]! {
var candidateAttributes: UICollectionViewLayoutAttributes?
for attributes in attributesForVisibleCells {
// == Skip comparison with non-cell items (headers and footers) == //
if attributes.representedElementCategory != UICollectionElementCategory.Cell {
continue
}
if let candAttrs = candidateAttributes {
let a = attributes.center.x - proposedContentOffsetCenterX
let b = candAttrs.center.x - proposedContentOffsetCenterX
if fabsf(Float(a)) < fabsf(Float(b)) {
candidateAttributes = attributes
}
} else { // == First time in the loop == //
candidateAttributes = attributes
continue
}
}
return CGPoint(x : candidateAttributes!.center.x - halfWidth, y : proposedContentOffset.y)
}
}
// Fallback
return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
}
}