This question already has answers here:
How to scroll to a particluar index in collection view in swift
(8 answers)
Closed 5 years ago.
I have horizontal UICollectionView, and i want to reset it X position. I tried following:
let indexPath = IndexPath(row: 0, section: 1)
self.collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition(rawValue: 0), animated: false)
However it not work, i got an error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'attempt to scroll to invalid index path: <NSIndexPath: 0x61000002d040> {length = 2, path = 1 - 0}'
How to scroll collection view to start?
This will not work if there are no items
self.collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition(rawValue: 0), animated: false)
Use (Objective C):
CGPoint topOffest = CGPointMake(0,-self.collectionView.contentInset.top);
[self.collectionView setContentOffset:topOffest animated:YES];
Use (Swift):
let topOffest:CGPoint = CGPoint(0,-self.collectionView.contentInset.top)
collectionView?.setContentOffset(topOffest, animated: true)
self.collectionView.scrollToItem(at: [0,5], at:.centeredHorizantally, animated: false)
0 represents the Section Number 0
5 represents Cell no 5
Related
I'm building an app where rows containing messages are inserted at the end of a table
messages.append(message)
let indexPath:IndexPath = IndexPath(row:(messages.count - 1), section:0)
tableView.insertRows(at: [indexPath], with: .none)
I then scroll to the bottom of the table
DispatchQueue.main.async {
let indexPath = IndexPath(
row: self.numberOfRows(inSection: self.numberOfSections - 1) - 1,
section: self.numberOfSections - 1)
self.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
Like other messaging apps, I would like to modify this so that the autoscrolling only happens if you're already scrolled at the end of the table instead of every time a new message gets inserted.
I've tried several techniques like detecting if the last cell is full visible https://stackoverflow.com/a/9843146/784637, or detecting when scrolled to the bottom https://stackoverflow.com/a/39015301/784637.
However my issue is that because scrollToRow sets animated:true, if a new message comes in but the previous message which came a split second before is still being scrolled down to via scrollToRow, then the autoscrolling to newest message and subsequent messages doesn't occur - ex. the last cell won't be fully visible until the animation is complete, or detecting if you're scrolled to to the bottom will be false until the animation is complete.
Is there any way I can get around this without setting animated: false?
What I would do is insert the row in a batch operation to make use of its completion handler, which serializes the UI update. Then I would check to see which rows are visible to the user and if the last couple of rows are, I think the user is close enough to the bottom of the conversation to force a down scroll.
let lastRow = IndexPath(row: messages.count - 1, section: 0)
DispatchQueue.main.async {
self.tableView.performBatchUpdates({
self.tableView.insertRows(at: [lastRow], with: .bottom)
}, completion: { (finished) in
guard finished,
let visiblePaths = self.tableView.indexPathsForVisibleRows else {
return
}
if visiblePaths.contains([0, messages.count - 2]) || visiblePaths.contains([0, messages.count - 1]) { // last 2 rows are visible
DispatchQueue.main.async {
self.tableView.scrollToRow(at: lastRow, at: .bottom, animated: true)
}
}
})
}
I'm getting following exception at run time randomly. How do I stop it happening?
Fatal Exception: NSRangeException
-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:usingPresentationValues:]: row (0) beyond bounds (0) for section (0)
Code:
self.table.reloadData()
let lastIndexPath = IndexPath(row: 0, section: 0)
self.table.scrollToRow(at: lastIndexPath, at: UITableView.ScrollPosition.top, animated: false)
self.table.isHidden = false
Yes, there are many similar/equal questions, but none worked for me.
I've a UITableView with some sections. The rows of these sections are created conform user put information in the table, so I want to auto-scroll when user type a especific field, but I don't know which IndexPath I must use to use the function:
UITableView.scrollToRow(at: IndexPath, at: UITableViewScrollPosition.middle, animated: true )
The problem is that I've section without rows, so I can't use the function above without especific a row in IndexPath. (In this case, the section without rows is the 3rd).
I already tried this:
let sectionRect : CGRect = tableViewOrder.rect(forSection: 3)
tableViewOrder.scrollRectToVisible(sectionRect, animated: true)
and
tableViewOrder.scrollToRow(at: IndexPath(row: NSNotFound, section: 3), at: UITableViewScrollPosition.middle, animated: true)
Both not works.
You can try
tableViewOrder.contentOffset = CGPoint(x:0,y: tableViewOrder.contentSize.height - tableViewOrder.frame.height)
So I have a UICollectionView that sort of houses a chat function in my app. As users send new messages they are brought in to the app via an observer pattern. However when new content comes in. It ends up below the keyboard and never adjust itself up. When I toggle the keyboard I have a function like this which seems to accomplish this goal. However, when I try similar code in my completion handler it fails and gives me this message.
'NSInvalidArgumentException', reason: 'attempt to scroll to invalid index path: {length = 2, path = 0 - 9}'
*** First throw call stack:
fileprivate func tryObserveComments(){
print(eventKey)
commentHandle = ChatService.observeMessages(forChatKey: eventKey) { (ref, newComments) in
self.commentRer = ref
self.comments.append(newComments!)
self.adapter.performUpdates(animated: true)
let item = self.collectionView.numberOfItems(inSection: self.collectionView.numberOfSections - 1) - 1
let insertionIndexPath = IndexPath(item: item, section: self.collectionView.numberOfSections - 1)
self.collectionView.scrollToItem(at: insertionIndexPath, at: UICollectionViewScrollPosition.top, animated: true)
}
}
Also for some reason in the strange instance that it does work. Some of the keyboard is partially covering the cell
Try it using performBatchUpdates, i think it will work as you excepted
fileprivate func tryObserveComments(){
print(eventKey)
commentHandle = ChatService.observeMessages(forChatKey: eventKey) { (ref, newComments) in
self.commentRer = ref
self.comments.append(newComments!)
self.adapter.performUpdates(animated: true)
self.collectionView.performBatchUpdates({
let item = self.collectionView.numberOfItems(inSection: self.collectionView.numberOfSections - 1) - 1
let insertionIndexPath = IndexPath(item: item, section: self.collectionView.numberOfSections - 1)
}, completion: { (Bool) in
self.collectionView.scrollToItem(at: insertionIndexPath, at: UICollectionViewScrollPosition.top, animated: true)
})
}
}
I have a chat Application in which messages are being fetched and updated in my tablview using NSFetchResultsController.
Here is my code:
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
{
self.tblViewChatLog.endUpdates()
scrollToBottom(animated: true)
if self.fetchedResultsController.fetchedObjects?.count == 0 {
}
else {
}
}
func scrollToBottom(animated: Bool)
{
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)
{
let secCount = self.tblViewChatLog.numberOfSections
if secCount > 0
{
let sections = self.fetchedResultsController.sections
let secInfo = sections?.last
let rows = secInfo?.objects //secInfo?.numberOfObjects
if (rows?.count)! > 0
{
let indexPath = NSIndexPath(row: (rows?.count)!-1, section: secCount-1)
self.tblViewChatLog.scrollToRow(at: indexPath as IndexPath, at: .bottom, animated: animated)
self.view.updateConstraintsIfNeeded()
self.tblViewChatLog.updateConstraintsIfNeeded()
}
}
}
}
I'm getting following error while trying to update my table.
Terminating app due to uncaught exception 'NSRangeException', reason: '-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (1) beyond bounds (1) for section (0).'
*** First throw call stack:
(0x21f15b0b 0x216d2dff 0x21f15a51 0x2672a9c1 0x2672a45f 0x13e7b4 0x54e90 0x19adba7 0x19b78e9 0x19adb93 0x19c156d 0x19afb43 0x19b2157 0x21ed7755 0x21ed5c4f 0x21e241c9 0x21e23fbd 0x23440af9 0x2655c435 0xcc554 0x21ad0873)
libc++abi.dylib: terminating with uncaught exception of type NSException
The error tells you that your table does not have any row at index 1. It means that your table view consists of 1 row and maximum range of indexPath.row can be 0 (because row index of a UITableView starts from 0). Whenever you will call a row at index path beyond range of the table, it will throw an error.