tableView.scrollToRow behaves differently with a small number of cells | iOS - ios

I'm trying to give a tableView and searchBar (tableView.tableHeaderView = searchBar) the same behavior as in the Messages and Mail apps i.e. hide the searchBar off the top of the parent view and scroll to show it.
The problem is the search bar is shown/hidden differently when the tableView has a different number of cells. How do I hide the search bar every time?
Not enough cells to fill the view
Just enough cells to fill the view
More than enough cells to fill the view
The method I'm using is tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)

Related

Animation in UITableViewCell breaks after cell deallocation

I have an expanding view in the cell. After i press show more button it works fine. But when i scroll down and that cell deallocates from memory and then i tap on show more button again animation breaks. How can i fix it?
Project repo on Github
Collapsed view:
Expanded view:
Debugger view, before scroll:
After cell deallocation (after scroll) breaks like this, expands behind second cell:
Based on your code and comment...
Instead of expanding your cell, you're setting clipsToBounds = false and expanding the cell's contents, allowing them to extend outside the bounds of the cell.
As you scroll a UITableView, cells are - of course - added / removed as needed. But when they are re-added, the "z-order" changes (because, with "standard" table view usage, it doesn't matter).
So, after scrolling down and then back up, and then tapping the "Show more" button, that cell may be (and usually is) at a lower z-order ... and thus its expanded "out-of-bounds" content is hidden behind the cell(s) below it.
If you want to stick with that approach (as opposed to expanding the cell itself), you can try implementing scrollViewDidScroll to make sure that cell is "on the top":
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// make sure the first row is visible (not scrolled off the top of the view)
let pth = IndexPath(row: 0, section: 0)
if let a = tableView.indexPathsForVisibleRows,
a.contains(pth),
let c = tableView.cellForRow(at: pth) {
// bring it to the front -- i.e. the top of the z-order
tableView.bringSubviewToFront(c)
}
}

Alternatives to tableView.scrollToRow()

Problem
I need to have a UITableView reload with a specific cell positioned at the top of the tableview. For instance, have the 3rd cell in the tableView appear at the top of the tableView, rather than the 1st.
The issue in doing this comes from not being able to use the
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
function, because I have a custom header that expands and collapse when the user scrolls. That means when I call the scrollToRow() function, my header collapses, messing things up.
Question
Is there any way to have a tableView open/reload with the 3rd cell positioned at the top of the tableView without using a "scroll" function?
Thanks!
You can follow below steps to fulfill your requirement:
Identify NSIndexPath of one of the visible cells.
Get its rectForRowAtIndexPath.
Get the current contentOffset of the table, itself.
Or, you can use scrollRectToVisible
This is how we use contentOffset:
mainTableView.setContentOffset(rectForRowAtIndexPath.point, animated: true)
And scrollRectToVisible:
mainTableView.scrollRectToVisible(rectForRowAtIndexPath.point, animated: true)

What is the expected `contentOffset` of UITableView when calling reloadData()?

I have a UITableView that displays custom cells. By pressing a button, the user can change the content of my UITableView
Scenario:
Load an array with 1000 elements
Scroll table to bottom (gives me about 20,000 contentOffset.y after scrolling)
On button pressed, I replace my array with 300 elements
Call reloadData in main thread (gcd)
After the step 4, what should be the correct new immediate contentOffset.y of my UITableView? I expected it to be 0 and my table scroll to top but for some reason it's not and does not scroll back to top. Is this the normal behavior of UITableView?
From Apple's docs... https://developer.apple.com/reference/uikit/uitableview/1614862-reloaddata
For efficiency, the table view redisplays only those rows that are
visible. It adjusts offsets if the table shrinks as a result of the
reload.
So, yes, it's normal to not scroll all the way to the top on reloadData.
If you want it to scroll to the top, either use setContentOffset or:
.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: false)
Yes, It is normal behavior of UITableView. If you an want that table view should scrolled to top after reloading, you have to do that using below code.
let newOffset = CGPoint(x: currentOffset.x, y: 0)
tableView.setContentOffset(newOffset, animated: false)
Automatically, UITableView retain it's scroll offset while reloadData function called.

Deleted row in tableView hide a second tableView in the same controller

I've an UITableViewController within an UITableView(named: AutocompleteTableView) that appears only when i'm editing a textfield in the UITableViewController.
I draw UITableView(AutoCompleteTableView) looking for the coordinates for the second section of my UITableViewController.
I'm scrolling the UITableViewController to the second section with :
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: self.tableView.numberOfRowsInSection(1) - 1, inSection:
1), atScrollPosition: UITableViewScrollPosition.Top, animated: true)
After scrolled the UITableViewController I draw the coordinates for the UITableView(AutoCompleteTableView) with :
autocompleteTableView.frame = CGRectMake(0, self.tableView.rectForSection(1).maxY, self.view.frame.width, (self.tableView.contentSize.height - self.tableView.rectForSection(1).maxY))
So, when I started writing in the textfield, the AutocompleteTableView appears in the correct position, but when I deleted a row from this section, the AutoCompleteTableView never again appears while I start to writing in the TextField.
I'm calling the two funcs (Scroll, and Draw) in the
textfieldShouldChangeCaracter func.

Align row middle with UITableView middle

I have a UITableView that should show a particular row in its middle when it is first displayed. In viewDidLoad, I use scrollToRowAtIndexPath to achieve this:
// Center vertically on current row
let scrollIndexPath = NSIndexPath(forRow: currentRow, inSection: 0)
tableView.scrollToRowAtIndexPath(scrollIndexPath, atScrollPosition: UITableViewScrollPosition.Middle, animated: false)
This makes the top of the current row aligned with the middle of the table view meaning that the content of the row looks lower than it should be. How can I make the middle of the row align with the middle of the table view?
UITableView is a subclass of UIScrollView so you can use:
scrollRectToVisible:<#(CGRect)#> animated:<#(BOOL)#>
and calculate CGRect yourself, this way you have way more control than with using:
scrollToRowAtIndexPath

Resources