Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView auto scroll to cell at IndexPath

Before loading the collection view user sets the number of image in the array of collection view. All of the cells don't fit on the screen. I have 30 cells and only 6 on the screen.

The question: How to scroll to the cell with desired image automatically at the load of UICollectionView?

like image 424
AlexanderZ Avatar asked Apr 13 '13 07:04

AlexanderZ


People also ask

How do I make UICollectionView scroll horizontally programmatically?

Add a UICollectionView to your view controller using the story board or programmatically. Add constraints to the newly added UICollectionView. It's important to have a fixed height for this collection view as it will scroll in one direction. Set the scroll direction to horizontal.

What is IndexPath Collectionview?

Locating Items and Views in the Collection View Gets the index path of the item at the specified point in the collection view. var indexPathsForVisibleItems: [IndexPath] An array of the visible items in the collection view.

What is swift UICollectionView?

An object that manages an ordered collection of data items and presents them using customizable layouts.


9 Answers

New, Edited Answer:

Add this in viewDidLayoutSubviews

SWIFT

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let indexPath = IndexPath(item: 12, section: 0)
    self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
}

Normally, .centerVertically is the case

ObjC

-(void)viewDidLayoutSubviews {
   [super viewDidLayoutSubviews];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
   [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}

Old answer working for older iOS

Add this in viewWillAppear:

[self.view layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
like image 51
boweidmann Avatar answered Oct 05 '22 13:10

boweidmann


I've found that scrolling in viewWillAppear may not work reliably because the collection view hasn't finished it's layout yet; you may scroll to the wrong item.

I've also found that scrolling in viewDidAppear will cause a momentary flash of the unscrolled view to be visible.

And, if you scroll every time through viewDidLayoutSubviews, the user won't be able to manually scroll because some collection layouts cause subview layout every time you scroll.

Here's what I found works reliably:

Objective C :

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // If we haven't done the initial scroll, do it once.
    if (!self.initialScrollDone) {
        self.initialScrollDone = YES;
    
        [self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
                                    atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
    }
}

Swift :

 override func viewWillLayoutSubviews() {

    super.viewWillLayoutSubviews()

      if !self.initialScrollDone {

         self.initialScrollDone = true
         self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
    }

}
like image 45
LenK Avatar answered Oct 05 '22 14:10

LenK


I totally agree with the above answer. The only thing is that for me the solution was set the code in viewDidAppear

viewDidAppear 
{
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
}

When I used the viewWillAppear the scrolling didn't work.

like image 25
raistlin Avatar answered Oct 05 '22 12:10

raistlin


Swift:

your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

Swift 3

let indexPath = IndexPath(row: itemIndex, section: sectionIndex)

collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)

Scroll Position:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically
like image 22
Rajesh Loganathan Avatar answered Oct 05 '22 14:10

Rajesh Loganathan


this seemed to work for me, its similar to another answer but has some distinct differences:

- (void)viewDidLayoutSubviews
{     
   [self.collectionView layoutIfNeeded];
   NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
   NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
   NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];

   [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
like image 29
greenhouse Avatar answered Oct 05 '22 14:10

greenhouse


You can use GCD to dispatch the scroll into the next iteration of main run loop in viewDidLoad to achieve this behavior. The scroll will be performed before the collection view is showed on screen, so there will be no flashing.

- (void)viewDidLoad {
    dispatch_async (dispatch_get_main_queue (), ^{
        NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    });
}
like image 28
Tianyu Wang Avatar answered Oct 05 '22 12:10

Tianyu Wang


I would recommend doing it in collectionView: willDisplay: Then you can be sure that the collection view delegate delivers something. Here my example:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    /// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
    if !didScrollToSecondIndex {
        self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
        didScrollToSecondIndex = true
    }
}
like image 41
Eike Avatar answered Oct 05 '22 13:10

Eike


As an alternative to mentioned above. Call after data load:

Swift

collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)
like image 36
nCod3d Avatar answered Oct 05 '22 12:10

nCod3d


All answers here - hacks. I've found better way to scroll collection view somewhere after relaodData:
Subclass collection view layout what ever layout you use, override method prepareLayout, after super call set what ever offset you need.
ex: https://stackoverflow.com/a/34192787/1400119

like image 45
trickster77777 Avatar answered Oct 05 '22 14:10

trickster77777