21

Why scrollToItem isn't working in my CollectionView? I want to work scrollToItem on EnabledID. So what's a problem and how fixed it?

Code:

var dataArray = NSMutableArray() // dataArray is has a data from Database
var EnabledID = Int()

EnabledID = UserDefaults.standard.integer(forKey: "EnabledID")
    
if EnabledID == 0 {
        
    EnabledID = 1
    UserDefaults.standard.set(1, forKey: "EnabledID")
        
} else {
    if EnabledID < dataArray.count {
        let index = NSIndexPath(item: EnabledID, section: 0)
        self.myCollectionView.scrollToItem(at: index as IndexPath, at: .centeredVertically, animated: true)
    }
}
    
Imran Rasheed
  • 825
  • 10
  • 25
developer1996
  • 827
  • 2
  • 14
  • 26
  • notice that, if you have dynamic size cells, scrolling will not work properly for some reason: http://www.openradar.me/37836568 https://github.com/airbnb/MagazineLayout/issues/68 – Zaporozhchenko Oleksandr May 27 '21 at 15:16

13 Answers13

56

Try this code...

Objective-C

[collectionView setDelegate:self];
[collectionView reloadData];
[collectionView layoutIfNeeded];
[collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:YES];

Swift - 4.x

collectionView.delegate = self
collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: true)

When the scroll direction is horizontal you need to use left,right or centeredHorizontally.

top is for the vertical direction.

collectionView.scrollToItem(at: index, at: .top, animated: true)
Ramkumar Paulraj
  • 1,841
  • 2
  • 20
  • 40
34

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)
tal marom
  • 441
  • 4
  • 4
10

My problem is a little weird. My iPhone 6/7/8 works fine, but iPhone X or 11 cannot scroll to my expected position. My original code is :

collectionView.reloadData()
collectionView.scrollToItem(at: IndexPath(item: 10, section: 0), at: .top, animated: true)

After I add collectionView.layoutIfNeeded(). Problem solves on my iPhone X and 11.

collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.scrollToItem(at: IndexPath(item: 10, section: 0), at: .top, animated: true)

This answer is inspired by @ram. He should get the credit. Add this answer is just to emphasize the difference between different iPhones. So people can search their answer quicker.

Wu Yuan Chun
  • 1,116
  • 11
  • 11
5

I use such workaround:

collectionView.isPagingEnabled = false
collectionView.scrollToItem(
    at: /* needed IndexPath */,
    at: .centeredHorizontally,
    animated: true
)
collectionView.isPagingEnabled = true

I've found such solution in several posts here and here.

Aleksey Shevchenko
  • 1,159
  • 1
  • 11
  • 23
3

try this.it is work for me

func scrollToIndex(index:Int) {
     let rect = self.collectionView.layoutAttributesForItem(at:IndexPath(row: index, section: 0))?.frame
     self.collectionView.scrollRectToVisible(rect!, animated: true)
 }
2

It won't work because contentSize is probably (0,0). If you not wish to use layoutIfNeeded() (because maybe you could be performing some undesirable an unnecessary stuff there), you should calculate it yourself (assuming your data is loaded, and the view did layout).

Swift 5.2

    collection.contentSize = CGSize(width: collection.bounds.width * CGFloat(items.count), height: collection.bounds.height)
    collection.scrollToItem(at: IndexPath(row: startingIndex, section: 0), at: .left, animated: false)
Federico Picci
  • 1,105
  • 10
  • 17
1

Try this for horizontal collection view

var isViewDidLayoutCallFirstTime = true


override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    guard self.isViewDidLayoutCallFirstTime else {return}
    self.isViewDidLayoutCallFirstTime = false
    self.collectionView.collectionViewLayout.collectionViewContentSize // It will required to re calculate collectionViewContentSize in internal method 
    let indexpath = IndexPath(item: self.currentIndex, section: 0)

    self.collectionView.scrollToItem(at: indexpath, at: UICollectionViewScrollPosition.centeredHorizontally, animated: false)

}
Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98
1

I've encountered this issue on iOS 14.x and Xcode 12.x.

The solution that worked for me was to use:

collectionView.scrollRectToVisible(rect, animated: true)
shim
  • 9,289
  • 12
  • 69
  • 108
Andrei Traciu
  • 267
  • 2
  • 2
1
collectionView.collectionViewLayout.invalidateLayout()
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
collectionView.collectionViewLayout.invalidateLayout()
Ilya
  • 11
  • 1
0

In my case .centeredVertically had no effect and was failing quietly. .centeredHorizontally fixed it

Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
0
 var scrollImg: Int = 0

override func viewDidLoad() {
    super.viewDidLoad()
    _ = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)

}

   @objc func autoScroll() {
    
    let totalCount = imageArray.count-1
    
    if scrollImg == totalCount{
        scrollImg = 0
    }else {
        scrollImg += 1
    }
    
    DispatchQueue.main.async {
        let rect = self.listOfViewsCollectionViews.layoutAttributesForItem(at: IndexPath(row: self.scrollImg, section: 0))?.frame
        if self.scrollImg == 0{
            self.listOfViewsCollectionViews.scrollRectToVisible(rect!, animated: false)
        }else {
            self.listOfViewsCollectionViews.scrollRectToVisible(rect!, animated: true)
        }
    }
}
Sahil Omer
  • 163
  • 9
0

if you want to chance scrollToItem in viewDidLoad, it's won't work

do it in viewDidLayoutSubviews or viewDidAppear

override func viewDidLayoutSubviews() {
             collectionView.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: true)
    }

or

    override func viewDidAppear(_ animated: Bool) {
        collectionView.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: true)
    }
Erhan Demirci
  • 4,173
  • 4
  • 36
  • 44
-3

Use This

self.messageCV.reloadData()
let indexPath = IndexPath(row: 0, section: 0)
self.messageCV.scrollToItem(at: indexPath, at: .bottom, animated: true) // .top
Vishal Vaghasiya
  • 4,618
  • 3
  • 29
  • 40