Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to scroll UICollectionViewCell programmatically in IOS?

I have a vertical UICollectionView with each cell taking up the entire self.view.frame I can easily swipe upwards to page to the next cell, but I would like to do the same thing with the press of a button.

I've tried using:

- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated

And:

- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated

They work but they temporarily "White-Out" the currentCell to present the nextCell, while the swiping shows both cells during the transition.

Ideally I would like to use:

- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated

But I don't know how to access the nextCell's indexPath... I've tried:

NSIndexPath *nextIndexPath = [_collectionView indexPathForItemAtPoint:CGPointMake(25, (_collectionView.frame.size.height-25)*(_currentIndexRowForCellOnScreen+1))];

Where _currentIndexRowForCellOnScreen is the indexPath.row of the UICollectionView's first appearance on screen in:

- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

But when I put it into:

- (NSIndexPath *)indexPathForCell:(UICollectionViewCell *)cell

it returns NULL after the first Cell, and does not animate....

Any direction would be greatly appreciated. Thank you for your time.

like image 1000
Rhotick Avatar asked Feb 03 '14 23:02

Rhotick


3 Answers

Assuming your collectionView contains only 1 section, and given that each item occupies the whole frame then you could do something like this;

  NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
  NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
  NSIndexPath *nextItem = [NSIndexPath indexPathForItem:currentItem.item + 1 inSection:currentItem.section];
  [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
like image 157
MDB983 Avatar answered Oct 19 '22 07:10

MDB983


By far this is the best approach i have encountered, the trick is to scroll to the frame which is containing next objects. Please refer the code

@IBAction func actionPreviousFriends(_ sender: Any) {

    let collectionBounds = self.collectionView.bounds
    let contentOffset = CGFloat(floor(self.collectionView.contentOffset.x - collectionBounds.size.width))
    self.moveToFrame(contentOffset: contentOffset)
}

/* -------------- display next friends action ----------------*/
@IBAction func actionNextFriends(_ sender: Any) {

    let collectionBounds = self.collectionView.bounds
    let contentOffset = CGFloat(floor(self.collectionView.contentOffset.x + collectionBounds.size.width))
    self.moveToFrame(contentOffset: contentOffset)
}

func moveToFrame(contentOffset : CGFloat) {

    let frame: CGRect = CGRect(x : contentOffset ,y : self.collectionView.contentOffset.y ,width : self.collectionView.frame.width,height : self.collectionView.frame.height)
    self.collectionView.scrollRectToVisible(frame, animated: true)
}
like image 25
Mr. Bean Avatar answered Oct 19 '22 07:10

Mr. Bean


Here are the Swift versions

Swift 2

let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems()
let currentItem: NSIndexPath = visibleItems.objectAtIndex(0) as! NSIndexPath
let nextItem: NSIndexPath = NSIndexPath(forRow: currentItem.item + 1, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(nextItem, atScrollPosition: .Top, animated: true)

Swift 3, 4, 5

let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems as NSArray
let currentItem: IndexPath = visibleItems.object(at: 0) as! IndexPath
let nextItem: IndexPath = IndexPath(item: currentItem.item + 1, section: 0)
self.collectionView.scrollToItem(at: nextItem, at: .top, animated: true)
like image 7
Chathuranga Silva Avatar answered Oct 19 '22 08:10

Chathuranga Silva