UICollectionView scrollToItem Not Working in iOS 14 - ios

I'm using a collection view, UICollectionView, and it works absolutely great...except that I cannot scroll to any particular item. It seems to always scroll to the "middle" is my best guess. In any case, whatever I send to scrollToItem seems to have no effect on the scrolling. I've put it in various locations throughout my view controller but with no success.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let lastIndex = IndexPath(row: messages.count-1, section: 0)
self.messagesView.scrollToItem(at: lastIndex, at: .bottom, animated: true)
}

UICollection View has bug in iOS 14 with scrollToItem. In iOS 14 it will only work if collection view paging will be desable.
So i got a solution if we have to scroll with both manual and programatically.
Specially for iOS 14 and above
self.collView.isPagingEnabled = false
self.collView.scrollToItem(at: IndexPath(item: scrollingIndex, section: 0), at: .left, animated: true)
self.collView.isPagingEnabled = true

You could try putting the scrolling code in viewDidLayoutSubviews which should get called after all table cells are loaded, which means your messages.count should work. Also, make sure you only have a single section in your collection view.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.scrollToBottom()
}
func scrollToBottom() {
DispatchQueue.main.async {
let lastIndex = IndexPath(item: messages.count-1, section: 0)
self.messagesView.scrollToItem(at: lastIndex, at: .bottom, animated: true)
}
}

Swift 5 / iOS 15
I was facing the same problem, so I tried this one-line code and get it done.
// here we slect the required cell instead of directly scrolling to the item and both work same.
self.collectionView.selectItem(at: IndexPath(row: self.index, section: 0), animated: true, scrollPosition: .left)

This is what worked for me, in case you want paging enabled:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.isPagingEnabled = false
collectionView.scrollToItem(
at: IndexPath(item: 1, section: 0),
at: .centeredVertically,
animated: false
)
collectionView.isPagingEnabled = true
}

Related

How to detect if scrollToItem will scroll

I am trying to scroll a cell at a specific location (.bottom) and after the scroll animation finishes run some code. The problem is that scrollToItem function does not provide a completion handler therefor the only solution is to use the delegate (scrollViewDidEndScrollingAnimation). Using that I have one problem though, if the cell is already at that location .didEndScrollAnim. will never be called.
Is there a way to find if a cell is already at UICollectionView.ScrollPosition.bottom ?
collectionView.scrollToItem(at: indexPath, at: [.bottom,.centeredHorizontally], animated: true)
I want to be able to run a part of code when the cell is at the desired location [.bottom] and also animate the scroll if a scroll is needed.
Yes, you can use scrollViewDidEndDecelerating func and this func will call when scroll view grinds (comes) to a halt.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let secondItemIndex = IndexPath(item: 1, section: 0)
categoryCollectionView.selectItem(at: secondItemIndex, animated: true, scrollPosition: .centeredHorizontally)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let secondItemIndex = IndexPath(item: 2, section: 0)
categoryCollectionView.selectItem(at: secondItemIndex, animated: true, scrollPosition: .centeredHorizontally)
}
// Scroll way doesn't effect this func so you can specify any position as you want
I can think of a way, but it involves calling scrollViewDidScroll repeatedly, which does reduce the performance of the screen.
In the func scrollViewDidScroll:
if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
//reach bottom, here your code
}
I set the animated param to false and use UIView.animate() to detect the animation completion.
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
}, completion: { [weak self] _ in
// do something after scroll animation completed
}
)

UITableView add rows and scroll to bottom

I'm writing a table view where rows are added upon user interaction. The general behavior is simply to add a single row, then scroll to the end of the table.
This was working perfectly fine before iOS11, but now the scrolling always jumps from the top of the table instead of smoothly scrolling.
Here's the code that has to do with adding new rows:
func updateLastRow() {
DispatchQueue.main.async {
let lastIndexPath = IndexPath(row: self.currentSteps.count - 1, section: 0)
self.tableView.beginUpdates()
self.tableView.insertRows(at: [lastIndexPath], with: .none)
self.adjustInsets()
self.tableView.endUpdates()
self.tableView.scrollToRow(at: lastIndexPath,
at: UITableViewScrollPosition.none,
animated: true)
}
}
And
func adjustInsets() {
let tableHeight = self.tableView.frame.height + 20
let table40pcHeight = tableHeight / 100 * 40
let bottomInset = tableHeight - table40pcHeight - self.loadedCells.last!.frame.height
let topInset = table40pcHeight
self.tableView.contentInset = UIEdgeInsetsMake(topInset, 0, bottomInset, 0)
}
I'm confident the error lies within the fact that multiple UI updates are pushed at the same time (adding row and recalculating edge insets), and tried chaining these functions with separate CATransaction objects, but that completely messes up asynchronous completion blocks defined elsewhere in the code which update some of the cell's UI elements.
So any help would be appreciated :)
I managed to fix the issue by simply just calling self.tableView.layoutIfNeeded() before adjusting the insets:
func updateLastRow() {
DispatchQueue.main.async {
let lastIndexPath = IndexPath(row: self.currentSteps.count - 1, section: 0)
self.tableView.beginUpdates()
self.tableView.insertRows(at: [lastIndexPath], with: .none)
self.tableView.endUpdates()
self.tableView.layoutIfNeeded()
self.adjustInsets()
self.tableView.scrollToRow(at: lastIndexPath,
at: UITableViewScrollPosition.bottom,
animated: true)
}
}
Make sure that you are respecting the Safe Areas.
For more details, check: https://developer.apple.com/ios/update-apps-for-iphone-x/

UICollectionView scroll to item not working with horizontal direction

I have a UICollectionView within a UIViewController with paging enabled. For some strange reason collectionView.scrollToItem works when the direction of the collectionview is vertical but doesn't when direction is horizontal. Is this there something I'm doing wrong or is this supposed to happen?
//Test scrollToItem
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let i = IndexPath(item: 3, section: 0)
collectionView.reloadData()
collectionView.scrollToItem(at: i, at: .top, animated: true)
print("Selected")
}
For iOS 14
Apparently there is a new bug in UICollectionView that is causing scrollToItem to not work when paging is enabled. The work around is to disable paging before calling scrollToItem, then re-enabling it afterwards:
collectionView.isPagingEnabled = false
collectionView.scrollToItem(
at: IndexPath(item: value, section: 0),
at: .centeredHorizontally,
animated: true
)
collectionView.isPagingEnabled = true
Source: https://developer.apple.com/forums/thread/663156
For this part:
collectionView.scrollToItem(at: i, at: .top, animated: true)
When the scroll direction is horizontal you need to use at: left, at: right or at: centeredHorizontally. at: top is for vertical direction.
I had trouble implementing this in a flow layout with entered paging per item. The .centeredHorizontally just wouldn't work for me so i use scroll to rect and Check there is data before scrolling:
if self.collectionView?.dataSource?.collectionView(self.collectionView!, cellForItemAt: IndexPath(row: 0, section: 0)) != nil {
let rect = self.collectionView.layoutAttributesForItem(at: IndexPath(item: data[index], section: 0))?.frame
self.collectionView.scrollRectToVisible(rect!, animated: false)
}
Swift 5.1, Xcode 11.4
collectionView.scrollToItem(at: IndexPath(item: pageNumber , section: 0), at: .centeredHorizontally, animated: true)
self.collectionView.setNeedsLayout() // **Without this effect wont be visible**
I try a lot of things and fail. This saves my day.
func scrollToIndex(index:Int) {
let rect = self.collectionView.layoutAttributesForItem(at: IndexPath(row: index, section: 0))?.frame
self.collectionView.scrollRectToVisible(rect!, animated: true)
}
Reference: https://stackoverflow.com/a/41413575/9047324
I have this issue: when button tapped (for horizontal collection scroll to next item) it always returns to first item with UI bug.
The reason was in this parameter: myCollection.isPagingEnabled = true
Solution: just disable paging before scroll to next item, and enable it after scroll.
After adding items to collectionView and reloadData(), scrollToItem was not working because reloading data has not finished yet.
Because of this I added performBatchUpdates like this :
self.dataSource.append("Test")
self.collectionView.performBatchUpdates ({
self.collectionView.reloadData()
}, completion: { _ in
self.collectionView.scrollToItem(at: IndexPath(item: 3, section: 0),
at: .centeredHorizontally,
animated: false)
})
I know it's not about this question but it will be helpful for this title.
For me, I had to scroll collection view on main thread like:
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: .centeredHorizontally, animated: true)
}
This will not work if you call scrollToItem before viewDidLayoutSubviews. Using scrollToItem in viewDidLoad will not work. So call this function after viewDidLayoutSubviews() is completed.
For iOS 14+
It's so stupid but it works.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.collectionView.scrollToItem(at: i, at: .top, animated: true)
}
Swift 3:
This worked for me on horizontal collection view.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//Show 14th row as first row
self.activityCollectionView?.scrollToItem(at: IndexPath(row: 14, section: 0), at: UICollectionViewScrollPosition.right, animated: true)
}
You can choose whether the desired cell at index to be on right or left on scroll position.
UICollectionViewScrollPosition.right or UICollectionViewScrollPosition.left.
Swift 5 if with animation horizontally
func scrollToIndex(index:Int) {
self.collectionView?.scrollToItem(at: IndexPath(item: index, section: 0), at: .centeredHorizontally, animated: true)
}
Your example:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
print("Selected: \(indexPath.row)")
collectionView.reloadData()
}
As #Dheeraj Agarwal points out, none of the 'ScrollTo' functionality of UICollectionView OR UIScrollView will seem to work properly if it is called before the view has been laid out. To be accurate, I think they WORK, but the effects are immediately nullified because laying out a UICollectionView causes it to reset to its minimum bounds, probably because of all the cell layout functions that will trigger, and the fact its content size may change.
The solution is to make sure this function is called after layout occurs, but it's not that simple. It's entirely likely that a collection view may be told to layout its content again and again in response to various changes - setting delegates, the contents updating, the view controller being added to a parent and therefore changing size. Each time this happens it'll reset to 0:0 offset.
You'll therefore have to keep a reference to the desired offset / cell index / frame until such a time as you are CERTAIN there will be no more unexpected layout updates. You can't just nil it out immediately as your collection view's layout might change multiple times before the view appears. I'm currently storing a frame in an attribute and calling the function in layoutFrames every time (my collection view's parent is a custom view, not a view controller). Although this has the slightly annoying feature of scrolling back again if the user rotates their phone, I consider it acceptable since this is a custom keyboard and most users will work with it in one orientation or the other, they won't keep flipping their phone around just to select a single value.
Solutions like calling DispatchQueue.main.asyncAfter are fragile. They work because the function call gets delayed until after the first layout occurs, but this may not always-and-forever solve the problem.
I guess the 'Scroll To' functions were only ever intended to be used in response to direct user input after the collection view is already populated.
CollectionView.isPagingEnabled = false
CollectionView.scrollToItem(at:IndexPath(item: YourcellIndex(4), section: at which section you want cell(0)), at: .centeredHorizontally, animated: false)
CollectionView.layoutSubviews()
CollectionView.isPagingEnabled = true
sometimes you can set
collectionView.collectionlayout.invalidate()
collectionView.scrollToItem(row:2,section:0)
If you have networking which can make disturb main thread, you have to avoid or after finish that, have to apply this code.
for example
self.group.enter()
some thread
self.group.leave()

Scrolling bottom in tableview and performance

I need to scroll to bottom. I have a chat app like whatsapp. So when view appears table view should show last row. I am achiving this with following line and works nice.
tableView.setContentOffset(CGPointMake(0, CGFloat.max), animated: false)
Also I need to scroll to bottom when keyboard appears. I am using Auto Layout and above line is not working. For to do this i am using following line:
func scrollToLastRow(animated: Bool) {
if self.numberOfRowsInSection(0) > 0 {
self.scrollToRowAtIndexPath(NSIndexPath(forRow: self.numberOfRowsInSection(0) - 1, inSection: 0), atScrollPosition: .Bottom, animated: animated)
}
}
This is a extension for Tableview.
This solution is working fine when there is no too much message. Then I tried with 5000 messages (so tableview have 5000 rows, but i am paging them) And when keyboard appears i see cpu usage is %98-100. I think the second code is problem for pagination, it causes loading every message to ram and my app freezes and receiving ram warning.
How to scroll to bottom without any performance issue?
If you have pagination, you can try to only load your current page as well as the final page, assuming you have 20 messages in each page, in this case your table have 40 rows only. Then you can use your function:
func scrollToLastRow(animated: Bool) {
if self.numberOfRowsInSection(0) > 0 {
self.scrollToRowAtIndexPath(NSIndexPath(forRow: self.numberOfRowsInSection(0) - 1, inSection: 0), atScrollPosition: .Bottom, animated: animated)
}
}
try this method :
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
let numberOfSections = self.tableView.numberOfSections
let numberOfRows = self.tableView.numberOfRowsInSection(numberOfSections-1)
if numberOfRows > 0 {
let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
}
})
If your are creating IM app. I recommend you reverse the tableView.
So the first row appears at bottom, and don't needs scrolling at beginning anymore.
Here is a cocoapod could help: https://github.com/marty-suzuki/ReverseExtension
If you stil want to scroll to specific row
implement the UIScrollViewDelegate.scrollViewDidEndScrollingAnimation.
and goes like this.
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
if scrollView.contentSize.height > lastContentHeight {
self.tableView.scrollToBottom()
self.lastContentHeight = scrollView.contentSize.height
}
}

UITableView - scroll to the top

In my table view I have to scroll to the top. But I cannot guarantee that the first object is going to be section 0, row 0. May be that my table view will start from section number 5.
So I get an exception, when I call:
[mainTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
Is there another way to scroll to the top of table view?
UITableView is a subclass of UIScrollView, so you can also use:
[mainTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
Or
[mainTableView setContentOffset:CGPointZero animated:YES];
And in Swift:
mainTableView.setContentOffset(CGPointZero, animated:true)
And in Swift 3 & above:
mainTableView.setContentOffset(.zero, animated: true)
Note: This answer isn't valid for iOS 11 and later.
I prefer
[mainTableView setContentOffset:CGPointZero animated:YES];
If you have a top inset on your table view, you have to subtract it:
[mainTableView setContentOffset:CGPointMake(0.0f, -mainTableView.contentInset.top) animated:YES];
Possible Actions:
1
func scrollToFirstRow() {
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
2
func scrollToLastRow() {
let indexPath = NSIndexPath(forRow: objects.count - 1, inSection: 0)
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
}
3
func scrollToSelectedRow() {
let selectedRows = self.tableView.indexPathsForSelectedRows
if let selectedRow = selectedRows?[0] as? NSIndexPath {
self.tableView.scrollToRowAtIndexPath(selectedRow, atScrollPosition: .Middle, animated: true)
}
}
4
func scrollToHeader() {
self.tableView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
}
5
func scrollToTop(){
self.tableView.setContentOffset(CGPointMake(0, UIApplication.sharedApplication().statusBarFrame.height ), animated: true)
}
Disable Scroll To Top:
func disableScrollsToTopPropertyOnAllSubviewsOf(view: UIView) {
for subview in view.subviews {
if let scrollView = subview as? UIScrollView {
(scrollView as UIScrollView).scrollsToTop = false
}
self.disableScrollsToTopPropertyOnAllSubviewsOf(subview as UIView)
}
}
Modify and use it as per requirement.
Swift 4
func scrollToFirstRow() {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
It's better to not use NSIndexPath (empty table), nor assume that top point is CGPointZero (content insets), that's what I use -
[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
Hope this helps.
Swift 4:
This works very well:
//self.tableView.reloadData() if you want to use this line remember to put it before
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
DONT USE
tableView.setContentOffset(.zero, animated: true)
It can sometimes set the offset improperly. For example, in my case, the cell was actually slightly above the view with safe area insets. Not good.
INSTEAD USE
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
On iOS 11, use adjustedContentInset to correctly scroll to top for both cases when the in-call status bar is visible or not.
if (#available(iOS 11.0, *)) {
[tableView setContentOffset:CGPointMake(0, -tableView.adjustedContentInset.top) animated:YES];
} else {
[tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:YES];
}
Swift:
if #available(iOS 11.0, *) {
tableView.setContentOffset(CGPoint(x: 0, y: -tableView.adjustedContentInset.top), animated: true)
} else {
tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)
}
I've encountered an issue calling trying some of the methods on an empty tableView. Here's another option for Swift 4 that handles empty tableviews.
extension UITableView {
func hasRowAtIndexPath(indexPath: IndexPath) -> Bool {
return indexPath.section < self.numberOfSections && indexPath.row < self.numberOfRows(inSection: indexPath.section)
}
func scrollToTop(animated: Bool) {
let indexPath = IndexPath(row: 0, section: 0)
if self.hasRowAtIndexPath(indexPath: indexPath) {
self.scrollToRow(at: indexPath, at: .top, animated: animated)
}
}
}
Usage:
// from yourViewController or yourTableViewController
tableView.scrollToTop(animated: true)//or false
For tables that have a contentInset, setting the content offset to CGPointZero will not work. It'll scroll to the content top vs. scrolling to the table top.
Taking content inset into account produces this instead:
[tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:NO];
This code let's you scroll a specific section to top
CGRect cellRect = [tableinstance rectForSection:section];
CGPoint origin = [tableinstacne convertPoint:cellRect.origin
fromView:<tableistance>];
[tableinstance setContentOffset:CGPointMake(0, origin.y)];
Swift 5, iOS 13
I know this question already has a lot of answers but from my experience this method always works:
let last = IndexPath(row: someArray.count - 1, section: 0)
tableView.scrollToRow(at: last, at: .bottom, animated: true)
And this is especially true if you're working with animations (like keyboard) or certain async tasks—the other answers will often scroll to the almost bottom. If for some reason this doesn't get you all the way to the bottom, it's almost certainly because of a competing animation so the workaround is to dispatch this animation to the end of the main queue:
DispatchQueue.main.async {
let last = IndexPath(row: self.someArray.count - 1, section: 0)
self.tableView.scrollToRow(at: last, at: .bottom, animated: true)
}
This may seem redundant since you're already on the main queue but it's not because it serializes the animations.
Swift:
tableView.setContentOffset(CGPointZero, animated: true)
Swift 3
tableView.setContentOffset(CGPoint.zero, animated: true)
if tableView.setContentOffset don't work.
Use:
tableView.beginUpdates()
tableView.setContentOffset(CGPoint.zero, animated: true)
tableView.endUpdates()
Since my tableView is full of all kinds of insets, this was the only thing that worked well:
Swift 3
if tableView.numberOfSections > 0 && tableView.numberOfRows(inSection: 0) > 0 {
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
}
Swift 2
if tableView.numberOfSections > 0 && tableView.numberOfRowsInSection(0) > 0 {
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: true)
}
Adding on to what's already been said, you can create a extension (Swift) or category (Objective C) to make this easier in the future:
Swift:
extension UITableView {
func scrollToTop(animated: Bool) {
setContentOffset(CGPointZero, animated: animated)
}
}
Any time you want to scroll any given tableView to the top you can call the following code:
tableView.scrollToTop(animated: true)
I prefer the following, as it takes into account an inset. If there is no inset, it will still scroll to the top as the inset will be 0.
tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)
Swift :
if you don't have tableView header :
tableView.setContentOffset(CGPointMake(0, UIApplication.sharedApplication().statusBarFrame.height ), animated: true)
if so :
tableView.setContentOffset(CGPointMake(0, -tableViewheader.frame.height + UIApplication.sharedApplication().statusBarFrame.height ), animated: true)
In Swift 5 , Thanks #Adrian's answer a lot
extension UITableView{
func hasRowAtIndexPath(indexPath: IndexPath) -> Bool {
return indexPath.section < numberOfSections && indexPath.row < numberOfRows(inSection: indexPath.section)
}
func scrollToTop(_ animated: Bool = false) {
let indexPath = IndexPath(row: 0, section: 0)
if hasRowAtIndexPath(indexPath: indexPath) {
scrollToRow(at: indexPath, at: .top, animated: animated)
}
}
}
Usage:
tableView.scrollToTop()
Here's what I use to work correctly on iOS 11:
extension UIScrollView {
func scrollToTop(animated: Bool) {
var offset = contentOffset
if #available(iOS 11, *) {
offset.y = -adjustedContentInset.top
} else {
offset.y = -contentInset.top
}
setContentOffset(offset, animated: animated)
}
}
using contentOffset is not the right way. this would be better as it is table view's natural way
tableView.scrollToRow(at: NSIndexPath.init(row: 0, section: 0) as IndexPath, at: .top, animated: true)
This was the only code snippet that worked for me
Swift 4:
tableView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
tableView.setContentOffset(CGPoint(x: 0, y: -70), animated: true)
P.S. 70 is the height of my header and table view cell
func scrollToTop() {
NSIndexPath *topItem = [NSIndexPath indexPathForItem:0 inSection:0];
[tableView scrollToRowAtIndexPath:topItem atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
call this function wherever you want UITableView scroll to top
Swift 4 via extension, handles empty table view:
extension UITableView {
func scrollToTop(animated: Bool) {
self.setContentOffset(CGPoint.zero, animated: animated);
}
}
I use tabBarController and i have a few section in my tableview at every tab, so this is best solution for me.
extension UITableView {
func scrollToTop(){
for index in 0...numberOfSections - 1 {
if numberOfSections > 0 && numberOfRows(inSection: index) > 0 {
scrollToRow(at: IndexPath(row: 0, section: index), at: .top, animated: true)
break
}
if index == numberOfSections - 1 {
setContentOffset(.zero, animated: true)
break
}
}
}
}
I had to add the multiply by -1 * to the sum of the status bar and the navigation bar, because it was going that height off the screen,
self.tableView.setContentOffset(CGPointMake(0 , -1 *
(self.navigationController!.navigationBar.height +
UIApplication.sharedApplication().statusBarFrame.height) ), animated:true)
in swift
your row = selectioncellRowNumber
your section if you have = selectionNumber if you dont have set is to zero
//UITableViewScrollPosition.Middle or Bottom or Top
var lastIndex = NSIndexPath(forRow: selectioncellRowNumber, inSection: selectionNumber)
self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
Here Is The Code To ScrollTableView To Top Programatically
Swift:
self.TableView.setContentOffset(CGPointMake(0, 1), animated:true)
In Swift-3 :
self.tableView.setContentOffset(CGPoint.zero, animated: true)
If you need use Objective-C or you still in love:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Solution with scrollToRow which fixes the problem for empty TableView (needs for search).
import UIKit
extension UITableView {
public func scrollToTop(animated: Bool = false) {
if numberOfRows(inSection: 0) > 0 {
scrollToRow(
at: .init(row: 0, section: 0),
at: .top,
animated: animated
)
}
}
}

Resources