UITableView reload animation doesn't work properly - ios

I have a table view which reloads it data with animation on button tap. It was working great until there was one label with text.
I use this code to reload data with animation for one button (I have only one section):
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.right)
and this for another button:
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
And on the top of table view it works okay, but in the middle or in the end it scrolling.
Link for gif - https://giphy.com/gifs/l0DAHUyzm7BMGnKrm/html5
Then I added this code for reloading with animation:
let offset = tableView.contentOffset
tableView.beginUpdates()
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
tableView.endUpdates()
tableView.layer.removeAllAnimations()
tableView.setContentOffset(offset, animated: false)
Same code for .right animation. It fixed scrolling, but added another issue. Again on top of table view it works okay, but then... Watch gif please.
Link for gif - https://giphy.com/gifs/xT1R9Gfaa2po6dMf2U/html5
I'm using test data to fill table view, not fetching or something else.
Hope for help, thanks
EDIT:
I found that if I set standard cell height from code animation works nice, only in this case it works:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}

I found the problem. The problem was in cell height, animation was starting for estimated cell height in 44.0 and my cell height is 117.0. So this code fixed my problem:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}

Related

UITableView jumps up when I insert rows above the indexPaths that is on the screen

I am trying to add some rows in my table view. when inserting rows are above the rows which are on the screen, the table view jumps up. I want my table view to stay in the position it is already in when I insert rows above. Keep in mind: tableView jump to indexPath that it was showing but after adding rows above, bottom rows indexPaths changes and the new n'th indexPath is something else.
This is unfortunately not as easy task as one would think. Table view jumps when you add a cell on top because the offset is persisted and cells updated. So in a sense it is not the table view that jumps, cells jump since you added a new one on top which makes sense. What you want to do is for your table view to jump with the added cell.
I hope you have fixed or computed row heights because with automatic dimensions things can complicate quite a bit. It is important to have the same estimated height as actual height for row. In my case I just used:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 72.0
}
Then for testing purposes I add a new cell on top whenever any of the cells is pressed:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var offset = tableView.contentOffset.y
cellCount += 1
tableView.reloadData()
let paths = [IndexPath(row: 0, section: 0)]
paths.forEach { path in
offset += self.tableView(tableView, heightForRowAt: path)
}
DispatchQueue.main.async {
tableView.setContentOffset(CGPoint(x: 0.0, y: offset), animated: false)
}
}
So I save what the current offset of the table view is. Then I modify the data source (My data source is just showing number of cells). Then simply reload the table view.
I grab all the index paths that have been added and I modify the offset by adding the expected height of every added cell.
At the end I apply the new content offset. And it is important to do that in the next run loop which is easies done by dispatching it asynchronously on main queue.
As for automatic dimensions.
I would not go there but it should be important to have size cache.
private var sizeCache: [IndexPath: CGFloat] = [IndexPath: CGFloat]()
Then you need to fill the size cache when cell disappears:
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
sizeCache[indexPath] = cell.frame.size.height
}
And change the estimated height:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return sizeCache[indexPath] ?? 50.0
}
Also when modifying your offset you need to use estimated height:
paths.forEach { path in
offset += self.tableView(tableView, estimatedHeightForRowAt: path)
}
This worked for my case but automatic dimensions are sometimes tricky so good luck with them.

Adding new row to a tableview with dynamic height cells

I have a table view with cells having dynamic height. I want to add a new row on a button click. I am incrementing the number of rows in section value and reloading the table view.But this results in a crash.I tried this after commenting the following lines
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
This is working fine when these 2 delegate methods are commented.But I want to add a new row.Dynamic height cells should be possible .How can I achieve this?
You can do like this
numberOfItems += 1
let indexPath = IndexPath(row: self.numberOfItems - 1, section: 0)
self.tbl.beginUpdates()
self.tbl.insertRows(at: [indexPath], with: .automatic)
self.tbl.endUpdates()

Swift UIView Border adjusts after UITableView scrolling

I have a problem with my UITableView sections (and their height, I guess).
Within a section header, I have a view (named cornerRadiusView) within which there are few labels. These labels have dynamic content (fetched from a REST service). So whenever a UILabel height is increased, I am increasing the height of the cornerRadiusView to properly accommodate the content.
The problem is, all this works as expected only when I scroll my tableView. Till then, the heights are improper.
Here I am posting GIF to show what's going on.
I can give more details and code as needed. Could someone please look at where there is a problem?
You can use below functions
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
And reload table view in below method
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableview.reloadData()
}
And if you are maintaining dynamic height then manage those height in cell
override func layoutSubviews()
{
}

How do I reset tableview's contents height after hidden UIView

Hi I'm trying to resize tableview's height after hidden indicatorView.
self.tableView.reloadData()
self.refresher.endRefreshing()
self.indicator.stopAnimating()
self.indicatorView.isHidden = true
When I set indicatorView as hidden but TableView's height still has space of indicatorView's height.
Somehow, You need to implement tableView(_:heightForRowAt:). For example:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// pseudo:
/*
if a condition related to hide the indicator (for example response from calling an api to get some data) is true, retrun -for example 100-, else (the response has not been called yet) retrun another value.
*/
}
You can also check the indexPath.row for chaning a specific row height:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// check if it is the second row:
if indexPath.row == 1 {
}
}
So, after calling self.tableView.reloadData() it should be called and assign the new height for the row.
Hope this helped.
Embed tableView and indicatorView in a stackview.
Like in this answer, but with Vertical Axis.

FZAcordion TableView Text goes Beyond the bounds

I am new to IOS and anyhow i have implemented the FZAccordion from HERE. Now my problem is when i have a long text in header section and cells it goes beyond the bounds.So how can i get rid of this problem so that no matter how long is the text it always fits in the screen.
Thank you.
You can use
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView,estimatedHeightForRowAtindexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension}
This will automatically resizes your text in your cells.

Resources