reloadData only on tableView visible cells - ios

Is that possible? To reload only the cells that are visible in order to do it more efficient.

That's how table views work by default. The UITableView class never loads cells until they're about to appear onscreen, even when you call reloadData.

To reload visible cells of tableview in Swift 3.0:
guard let visibleRows = pTableView.indexPathsForVisibleRows else { return }
pTableView.beginUpdates()
pTableView.reloadRows(at: visibleRows, with: .none)
pTableView.endUpdates()

Try this, You can reload any cell of the tableview using reloadRowsAtIndexPaths:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];

Related

Maintain current position of UITableView while calling reloadData with variable height custom cells of UITableView

I have UITableView with variable height custom cells and multiple sections which are not fixed, i am trying to implement load more functionality while user reach at first cell.
After fetching data i am arranging records into NSMutableArray which contains multi-dimensional array to store data section vice.
My problem is when i load more data i don't have idea about how many sections and how many rows in each section comes. So i can not add fix values to move my UITableView at particular position using methods like scrollToRowAtIndexPath or scrollRectToVisible
So every time after getting new record i called reloadData to update my number Of Sections and number Of Rows In Each Section, which also move control to first row of UITableView. I want to be present at current viewing cell not at first cell.
I have also tried answers at reloadData() of UITableView with Dynamic cell heights causes jumpy scrolling this question but that are not helping me.
Don't use reloadData if you want to stay at the same position. Use reloadRowsAtIndexPaths or insertRowsAtIndexPaths or reloadSections instead.
To refresh modified rows with animation:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[indexPathOfYourModifiedCell] withRowAnimation: UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
To add rows with animation (number of rows is automatically increased):
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPathOfYourNewCell] withRowAnimation: UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
Without animation (untested):
[UIView performWithoutAnimation:^{
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPathOfYourNewCell] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}];
Apple documentation: description here

UITableView bouncing back to the top of a section when calling reloadRowsAtIndexPaths

When a user taps a button in one of my rows I am updating the underlying model for that row and then calling reloadRowsAtIndexPaths for the given row (i.e. single row reload).
- (IBAction)handleCompleteTouchEvent:(UIButton *)sender {
NSIndexPath *indexPath = [self.tableView indexPathForView:sender];
id item = [self dataForIndexPath:indexPath];
if ([item respondsToSelector:#selector(completed)]) {
// toogle completed value
BOOL completed = ![[item valueForKey:#"completed"] boolValue];
[item setValue:[NSNumber numberWithBool:completed] forKey:#"completed"];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
}
The problem is that the table view bounces back to the top of the section after making this call. How can I prevent this from occurring and keep the scroll position where it is?
Ah Ha! I found the problem and am going to answer my own question for the poor soul who runs into this issue in the future.
All of my cells have variable height so I was using the new iOS7 method in UITableViewDelegate thinking it might speed up render time (not that I really needed it):
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
Anyway, implementing this method has the evil side effect of causing the table to bounce to the top of the section when calling:
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
To solve the bounce problem I just removed the override of that estimatedHeightForRowAtIndexPath method and now everything works as it should. Happy at last.
This did the trick for me.
UIView.setAnimationsEnabled(false)
tableView.reloadRows(at: [...], with: .none)
UIView.setAnimationsEnabled(true)
Swift 4.2
This can work anywhere you want to remove animation.
During reload of table , table section or any row
UIView.performWithoutAnimation({
cell.configureSelection(isSelected: true)
tableView.reloadSections([1], with: .none)
tableView.allowsSelection = false
})
You should be able to do what you are trying to do by changing the cell contents directly. For example, if you are using the base UITableViewCell class and the data in your model is a NSString which you show in the table view cell, you can do the following (after you change your data model) instead of calling reloadRowsAtIndexPaths:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label = [cell textLabel];
label.text = #"New Value";
If you are using a custom subclass of UITableViewCell, it's roughly the same except for accessing the views of the cell will need to be done through the contentView property.
It may be possible to put the cell in it's own section and call reload section:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
this appears to fix the issue partially. Not the cleanest way but it may work for you.
In my similar case, I had to tweak the implementation of method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
...
}
where my heights were being reset. So, instead of resetting height for every cell I updated only the effected cells for reloadRowsAtIndexPaths call.
If you know the minimum height of your cell, you must specify that while setting estimatedRowHeight. I was setting it to 1 as I have read before somewhere that any value above 0 would suffice the purpose, but it was the culprit.
When I set it to 44, which was the minimum height my cell could have, all went fine.
Dynamic heights were also working fine, no issues with this fix.
To build off xsee's answer -
I had set the Estimate in interface builder to "automatic". I changed this to another number and it started working. I kept Row Height to automatic.
I had the same issue. I ended up just calling tableView.reloadData() instead after updating my data / cell and it didn't bounce back to the top / data was updated in place - FYI
This solved this issue for me with Swift 5 / iOS 14:
UIView.performWithoutAnimation({
self.tableView.reloadRows(at: [self.idxTouched], with: .none)
})

Dynamic UITableViewCell with UIWebView

I have an array of HTML strings, some of them are with photos, some of them long, some short, some with links - they are all different.
Now I have a UITableView and I want to display those HTML strings on the table, each string in each cell by it's index. My problem is that I don't know the height of each cell, I need to calculate the height by the height of each HTML string, but I can only know it after the UIWebView is loaded.
I need a suggestion for a good solution to this issue, something that will looks good. I've already tried to use UIWebViewDelegate to change the cell frame after loading the HTML string into the WebView but it looks bad.. and messes the table view completely.
Thanks in advance.
Resort to animation when adding the cells.
Add the cells one by one (1 indexPath at a time) in your UITableView (and datasource), by doing this:
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
// or UITableViewRowAnimationNone
[self.tableView endUpdates];
Your UITableView will slowly grow with an animation as the data becomes available.
If you need to resize an existing cell, delete it and immediately re-insert it, all within a single beginUpdates/endUpdates sequence:
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

iOS Table view cell not displaying properly after resize

I have set up my table view with 6 static cells and I'm trying to have one cell (the third cell) expand upon selection. The problem is, it resizes after calling reloadRowsAtIndexPaths:, but then the cell appears blank. If I scroll the cell out of view, it shows the contents properly.
When I call [tableView reloadData] the cell isn't blank, but then, I can't enjoy the animation.
Does anyone know why this is so?
Well if you set the height for a row then you need to reload the content of the cell NOT the content of the whole table. If you call [tableview reloadData] then it simply means that you redraw the whole table(without the height correction).
To reload a single cell in the table:
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
I don't know if I was the only one having the problem with a blank static cell issue.
I stumbled on a solution and that is calling [tableView reloadData] after calling reloadRowsAtIndexPaths:
Reload the respective table view row using the main thread.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Reload the respective table view row using the main thread.
[self.tblFiles reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:index inSection:0]]
withRowAnimation:UITableViewRowAnimationNone];
}];

iOS: move table cell to another section

I have a UITableView with some sections and rows.
I want to move one row from one section to another section, when I call a function (so not my fingers and I do not want use edit mode of UITableView).
How can I do this?
If I recreate a datasource and reload table, it's ok, but it not use animation.
UITableView offers you methods for this:
call beginUpdates, update your datasource, call moveRowAtIndexPath and finally call endUpdates on UITableView
[tableView beginUpdates];
// update your datasource
// ...
// fill in your indexpath of old and new position
[tableView moveRowAtIndexPath: ... toIndexPath: ...];
[tableView endUpdates];
EDIT: moveRowAtIndexPath is only for iOS 5+
so you would rather use this:
[tableView insertRowsAtIndexPaths: ... withRowAnimation:...];
[tableView deleteRowsAtIndexPaths: ... withRowAnimation:...];

Resources