After adding header view, scroll to bottom of UITableView cause NSException - ios

I have a method that scrolls my UITableView to the bottom:
func tableViewScrollToBottom(_ animated: Bool) {
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time, execute: {
print(self.tview.numberOfRows(inSection: 0))
print(self.tview.numberOfSections)
let indexPath = IndexPath(row: self.tview.numberOfRows(inSection: 0), section: self.tview.numberOfSections)
print(indexPath)
print("it will crash now")
self.tview.scrollToRow(at: indexPath, at: .bottom, animated: animated)
})
}
it worked well before, however when I added Header View - it crashes.
I see in the console:
8
1
[1, 8]
it will crash now
so I do not understand why this line:
self.tview.scrollToRow(at: indexPath, at: .bottom, animated: animated)
causes crash. What am I missing here?

You have problem with this
let indexPath = IndexPath(row: self.tview.numberOfRows(inSection: 0), section: self.tview.numberOfSections)
Try doing -1
let indexPath = IndexPath(row: self.tview.numberOfRows(inSection: 0)-1, section: self.tview.numberOfSections-1)

Related

Scrolling to bottom of a section in tableView

I am trying to write a function that scrolls to the bottom cell of a given section in my tableView, I'm calling this function after my tableView.reloadData() function but it is not scrolling, any ideas why?
func scrollToBottom(section: Int){
DispatchQueue.main.async {
let indexPath = IndexPath(row: self.session[section].count - 1, section: section)
self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
You don't need put code in DispatchQueue.main because it already run on main thread.
Try this
func scrollToBottom(section: Int){
let indexPath = IndexPath(row: self.session[section].count - 1, section: section)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}

Setting UITableView row selection programmatically returns nil

Trying to call a TableView row to be selected programatically.
All my delegates are set properly, and the UITableView is linked in IB. All other UITableView methods work properly, and are located in either the main ViewController or its extension. When the following is called I get Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value.
func selectTableViewRowProgrammatically () {
let indexPath = IndexPath(row: someVariable, section: 0)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableView.ScrollPosition.none)
tableView.delegate?.tableView!(self.tableView, didSelectRowAt: indexPath)
tableView.reloadData()
}
Error shows on self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableView.ScrollPosition.none)
Thanks!
can you try Following code
let indexPath = IndexPath(row: someVariable, section: 0)
UIView.animate(withDuration: 0.1, animations: {
tableView.scrollToRow(at: indexPath, at: .top, animated: false)
}) { (true) in
tableView.delegate?.tableView!(self.tableView, didSelectRowAt: indexPath)
}

Using an action to scroll CollectionView to the next cell

I have a horizontal collectionview that adds a new cell every time I tap the button. I am attempting to scroll the collectionview to the next cell once the cells are no longer visible each time I tap the button.
The code I have now is not working properly
Code:
#IBAction func random(_ sender: Any) {
resultsCollection.reloadData()
let collectionBounds = resultsCollection.bounds
let contentOffset = CGFloat(floor(resultsCollection.contentOffset.x - collectionBounds.size.width))
self.moveToFrame(contentOffset: contentOffset)
}
func moveToFrame(contentOffset : CGFloat) {
let frame: CGRect = CGRect(x : contentOffset ,y : resultsCollection.contentOffset.y ,width : resultsCollection.frame.width,height : resultsCollection.frame.height)
resultsCollection.scrollRectToVisible(frame, animated: true)
}
How can I fix this so that it scrolls correctly when I tap the button?
After reload your data, call this lines.
let lastItem = resultsCollection(resultsCollection, numberOfItemsInSection: 0) - 1
let indexPath = IndexPath(row: lastItem, section: 0)
resultsCollection.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
Use the following code to achieve your needs. For animation, you just need to pass value true/false in animated of scrollToRow function.
Hope this will help you!
To scroll top without animation
func scrollToTopWithoutAnimation() {
DispatchQueue.main.async {
if self.dataArray.count > 0 {
let indexPath = IndexPath(row: 0, section: 0)
collectionView.scrollToItem(at: indexPath, at: .top, animated: false)
}
}
}
To scroll top with animation
func scrollToTopWithAnimation() {
DispatchQueue.main.async {
if self.dataArray.count > 0 {
let indexPath = IndexPath(row: 0, section: 0)
collectionView.scrollToItem(at: indexPath, at: .top, animated: true)
}
}
}
Set IndexPath row as per your needs

How to focus last cell in the UITableview in ios

I am creating a chat interface.
User's message is put in a new UITable view cell.
And when update the table view, I use the following code.
extension UITableView {
func scrollToBottom() {
let rows = self.numberOfRows(inSection: 0)
if rows > 0 {
let indexPath = IndexPath(row: rows - 1, section: 0)
self.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
}
Actually this works a little better, but there is something strange.
When I turn off the app and turn it on again, or after exiting the screen and entering again, the following issues arise.
The issue is that when I add a new cell, it goes up to the first cell in the table view and back down to the last cell.
See the issue(https://vimeo.com/266821436)
As the number of cells increases, the scrolling becomes too fast and too messy.
I just want to keep updating the last cell that is newly registered.
What should I do?
Please use DispatchQueue to Scroll because of the method you are fire is executed with tableView load data so we need to give time to scroll.
extension UITableView {
func scrollToBottom() {
let rows = self.numberOfRows(inSection: 0)
if rows > 0 {
DispatchQueue.main.async {
let indexPath = IndexPath(row: rows - 1, section: 0)
self.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
}
}
or
func scrollToBottom(){
DispatchQueue.main.async {
let indexPath = IndexPath(row: self.array.count-1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
self.scrollToRow(at: indexPath.last ...)

iOS UITableViewController - Insert and Scroll to bottom - sometimes jumping

I'm developing an iOS Chat App and I have a problem on the chat view. I'm using UITableViewController for the chat view. Sometimes my table jumps when new row is inserted as you can see in video: https://youtu.be/8IgEUJ5uYAc .
This is how I'm inserting and scrolling to the bottom of the table:
self.conversation.append(message)
self.tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath(row: self.conversation.count - 1, section: 0)], with: UITableViewRowAnimation.none)
self.tableView.endUpdates()
DispatchQueue.main.async {
self.tableView.scrollToRow(at: IndexPath(row: self.conversation.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: false)
self.footerView?.isHidden = true
self.theMessage.text = nil
self.switchBottomActions(showSend: false)
}
Each message object has a property called estimatedMessageHeight. I'm saving there the message cell size, so tableView's heightForRowAt code is:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let cellHeight = self.conversation[indexPath.row].estimatedHeight else {
return 0
}
return cellHeight
}
Any solution?
I was also facing same issue and finally I ended up with following solution. It gives me same animation feel like we have in WhatsApp app.
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
let reloadIndexPath = IndexPath(item: self.arrTableVwData.count - 1, section: 0)
self.tableVw.beginUpdates()
self.tableVw.insertRows(at:[reloadIndexPath], with: UITableViewRowAnimation.fade)
self.tableVw.endUpdates()
self.tableVw.scrollToRow(at: reloadIndexPath, at: .bottom, animated: false)
}, completion: nil)
NOTE: please do not pass any animation types in options:[] as we already passing them in insertRows and scrollToRow methods.
Make this function:
func scrollToBottom(){
DispatchQueue.main.async {
let indexPath = IndexPath(row: self.chatListDB.count-1, section: 0)
self.tblView.scrollToRow(at: indexPath, at: .bottom, animated: false)
}
}
and call it after inserting the value.
You should uncheck Bounce Vertically in the Attribute Inspector for your UITableView.

Resources