UITableViewController scrollViewDidScroll: not called during cell removal - ios

I have a tableView whose content is smaller than the screen, so its not scrolling.
I'm reloading one of the sections when changing to editing mode, which causes the tableView to add rows.
When I now scroll down and then deactivate the editing mode, the tableView removes the redundant cells again and scrolls to top.
During this scroll operation I'm not getting any scrollView delegate calls.
For details, please check my implementation: GISTViewController.m

Well, after reading your question a few times, it looks like our issues aren't the same.
I believe your issue is because scrollViewDidScroll: is not called during some animations. You should see this answer here, though unaccepted (maybe because they imply user interaction is the only way to trigger it), it also contains a path to this answer about getting scrolling events during automated animations which may be of help.

Related

UITableView cells are unloaded too early after reordering

I've recently built in reordering into my UITableView but there's a nasty bug I'm experiencing after reordering the cells. The bug only occurs after a cell has been reordered: When scrolling the table view up, the cells visible at the bottom of the screen sometimes simply disappear while scrolling. It seems as if the cells are unloaded too early. This only happens when scrolling up. When scrolling down the bug doesn't exist. The cells that randomly disappear also re-appear when scrolling down once their empty space leaves the screen. Here's a screenshot of this issue:
I'm pretty sure that my data source isn't the problem because:
When reordering a cell my data source updates as well
I've checked the table view with Spark Inspector and the missing cells aren't simply hidden or empty but they just don't exist, there is no cell at all where the empty spaces are.
After scrolling around the cells re-appear, the cells randomly appear and disappear
It must be some bug or issue in UITableView, but I may also be wrong with that assumption. Maybe somebody has already faced this problem and can help me out now ;) I'm waiting for your answers :)
Edit:
I just checked the -tableView:didEndDisplayingCell:forRowAtIndexPath: delegate method and the cells are really unloaded normally and that method is called, even though the cells are still visible on the screen!
Edit (2):
I now know that the issue only occurs when my table view has a header view. It doesn't matter if I use the default header or a custom one, but whenever I use a header view I also get the bug. When I don't use a header it works just fine. Thats really strange
Note: I'm testing this on iOS 6.1.2

UITableViewController weird behavior after popping a view controller

My UITableView has a bunch of reusable cells, and when I tap on one of them, it takes me to another view controller (via push segue) showing the details of that cell (let's say it's an item, so it would show details about an item - name, price, image, etc...). When I pop that view controller (by tapping on the back button), the UITableView has a strange behavior:
a) if it's scrolled all the way to the bottom, it will scroll automatically tad up (around 50 points), leaving the last cell barely visible, so I have to scroll back down again. My cell all have 60 points for height.
b) the scrollbar always shows and then disappears, indicating that something is moving that UITableView (although if not scrolled to the bottom, the content will not move automatically).
This happens in multiple UITableView's I have in my app. I am not forcing a reload of the table view in viewWillAppear, so I don't understand what is happening. My content is static after loading from the server (unless the user changes it, and then the reload is executed). But simply showing details of an item and popping that VC doesn't change anything in the table view.
Edit: Okay, I've figured what the problem is: I'm hiding a UIToolbar when pushing that segue. If I keep it always visible (which I don't want), it still shows the scrollbars animating when popping in my table view but doesn't scroll the table view if on the last few rows.
Add the following to viewDidLoad.
self.automaticallyAdjustsScrollViewInsets = NO;
This solved my problem of table view moving down after navigating back to view controller.
I managed to fix the first issue. It seems like the tableview is not taking into account the 44 points of the UIToolbar.
Save the tableview offset in prepareForSegue: (save it in a CGPoint property)
self.tableViewScrollOffset = self.tableView.contentOffset;
Then, in viewWillAppear:, check if it has been modified. If so, restore it.
if(self.tableView.contentOffset.y != self.tableViewScrollOffset.y) {
[self.tableView setContentOffset:self.tableViewScrollOffset];
self.tableViewScrollOffset = CGPointZero;
}
This behavior is indeed a bug in iOS 8.x.
All answers given so far can not really solve the issue. The issue is, that iOS forgets (or doesn't) consider the previously calculated cell sizes, when a table is being redrawn for instance when the view is being pushed.
One approach to solve this can be found here: UITableView layout messing up on push segue and return. (iOS 8, Xcode beta 5, Swift) (so this question is even a duplicate to this one).
However, the solution provided there is overkill and there are certain situations why this caching will fail (for instance a UIContentSizeCategoryDidChangeNotification is not regarded)
But there is a quite simpler solution even though it is odd:
If you are using a manual performSequeWithIdentifier in didSelectRowAtIndexPath, just add a [self.tableView reloadData] just before.
If you are using a IB seque from the cell, just add [self.tableView reloadData] in your prepareForSeque code.
The reason, why this solves the issue is, that this will force iOS to re-estimate the visible cells and so it no longer scrolls the content to another location. Fortunately, tableView reloadData doesn't cost too much overhead here as only the visible cells will be re-estimated.
Just a hunch, have you got a rogue scrollToRowAtIndexPath:atScrollPosition:animated hanging around?
I was also facing this issue. I managed to find it out. The reason in my case is tableview header height was calculating based text and text height was negative due to which tableview was shifting down even though the contentinset and scrollinset are zero.
This was only occurring for first time. Next time it is calculating correct. One weired thing i found is that when Class A (having tableview) have pushed another Class B from init. When keyboard from Class B is opened viewDidLoad of Class A is called. and before Class B is unloaded from navigation controller. Tableview is reloaded for Class A.
Setting the automaticallyAdjustsScrollViewInsets as suggested above did not work neither did caching and setting the tableViewScrollOffset work.
Hence came up with an workaround which worked like a charm for me.
The workaround was to add an Dummy UIView which has height of 1px and width of 320px and place it between the "Top Layout Guide" and the UITableView. This view's background could be set to clear so that it is invisible.
Now using Autolayouts, fix the Dummy View's top to the Top. Now set the tableview's top constraint with respect to Dummy View. Found that this resolved the issue of the tableview's misplacement.
Screenshot of the Dummy View along with the autolayout constraints have been provided for easy reference. The Dummy View has been set to a larger height and red background colour for illustration purpose only.

UITableView Section Headers not visible when table in visible rect

I have a UIScrollView with 3 UITableViews stacked horizontally. I switch between these tableviews using a tab-controller on top. However, when I switch to the 2nd or 3rd tab and switch back quickly to 1st the section headers don't show. They display when I scroll the tableView. These are custom headers (jfyi). I tried calling setNeedsDisplay when the tableView is visible, but that does not help because as per Apple Docs :
If you simply change the geometry of the view, the view is typically not redrawn. Instead, its existing content is adjusted based on the value in the view’s contentMode property. Redisplaying the existing content improves performance by avoiding the need to redraw content that has not changed.
Since, only the geometry of the view is changing here, it does not help. Also this happens on all versions iOS 5~6.1 and on simulator and device. Thankfully, this does not crash the app, but its a problem nevertheless. Could someone help? I am attaching pictures for reference. First shows the problem, second: after scrolling the "head(er)less" tableview
EDIT:
I am using simple scrollRectToVisible:animated: to switch between tableviews. This does the trick but I just observed that when I set ...animated:NO all is okay. The problem happens when ...animated:YES
It seems the issue of displaying and scrolling taking place simultaneously for the respective tableview. So what you can do here is:
Remove the scroll animation
or
Just scroll the tableview to top on the tab press event
or
simply reload the tableView which is made visible

UITableView will not resize after UITextField becomes first responder

I have two Scenes in my Storyboard that are nearly identical. Both are UITableViewControllers. Both have header and footer views. The header views have a UISearchBar and the footer views have a UIView that contains a UITextField. Each have only one prototype cell. One is prototyped as a "Basic" cell and the other is prototyped as "Right Detail" cell.
Here's the problem. When I click the UITextField in the footer view on the first scene, the table resizes automatically so that the bottom of the table is at the top of the keyboard. This allows me to scroll the table up so the footer view shows and the user is able to see what they're typing. The other scene will not automatically resize the UITableView so the UITableView cannot scroll the footer view to where it can be seen and the UITextField is hidden under the keyboard. I can't even manually scroll the table far enough since the footer is always at the bottom of the UITableView.
A little added info. The scene that works has many rows of data while the one that doesn't work only has a couple. I tried adding a number of rows until the table had enough to enable scrolling and it doesn't fix the problem.
I have checked everything I can think of and I can't see anything that would allow one of the views to let the UITableView to automatically resize to work with the keyboard and the other not. I must have overlooked something but I can't seem to find it.
Any help will be greatly appreciated!
Rob
I thought this problem was caused by copy-and-pasting from one view to another, but I had the same problem once I'd (in theory) fixed it.
The answer for me turned out to be simple: I hadn't called [super viewWillAppear:animated] in my UITableViewController subclass' viewWillAppear: implementation. Make sure you've got a call to the superclass' method and hopefully the problem will go away.
I am guessing the frame of the tableview is not being resized to the smaller size in the second case.
Print out the frame and content sizes in both the cases once its loaded, that should help you see if there is an issue.

With multiple UITableViews in a single UIScrollview, how to only load cell data for visible cells

I have 3 uitableviews in a single uiscrollview. Each uitableview is full length and not scrollable so that the outer uiscrollview scrolls them together. This works fine except the uitableviews believe all cells are visible so that all are created up front. Even this is acceptable except each call has an image view (a thumbnail) that is loaded asynchronously from a url. I am trying to figure out how to limit the image loading to only visible cells but still allow the user to scroll the outer uiscrollview (thus mimicking the uitableview behavior).
The alternative design of a single table with cells that show 3 cells each doesn't work (based on other design requirements) so I am stuck with some way to limit the image downloads. The largest number of cells will be 125 or so. The uiscrollview delegate doesn't seem to have enough calls to allow updating cells on the fly but I could be wrong. Any ideas?
Maybe just do a custom check : if the tableView is not visible (because not in the bounds of your scrollView), then do not load the images (or the cells) of the tableView in "cellForRowAtIndexPath".
If the tableView is visible, then call reloadData and display the images.
You can check all this with the scrollViewDelegate methods.
TableViewDatasource Protocol implements:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
for a full table that is not in bounds you can limit update simply by comparing the tableview pointer parameter to your actively showing tableviews and skip your non-visible tableviews.
For Cells: This is a more difficult one considering that you are implementing 3 on the same scrollview. This would be a bit easier if you implemented 3 separate tableviews each that are standardly implemented. The reason for this statements is, that the routine if implemented above by Apple's protocol really does only get called for the cells that are currently needing to be on screen. In this way you could implement your image background loader inside of the above defined routine, and you would indeed get what you wish. I have done this and it does work.
Another answer:
perhaps you should look into a custom tableview where you define your own custom look and feel for a single tableview that incorporates all the information you wish into this single table thus allowing you to implement the other half stated just above.
To give a better answer, I think I would have to dig deeper into what you are attempting to ultimately accomplish.
Appears I can simply use the UIScrollViewDelegate scrollViewDidScroll call and then use the scrollview's contentOffset.y to trigger the thumbnail for any cells which are visible (or about to be) using tableView indexPathsForRowsInRect for each tableview. My cell subclass has a method to trigger the thumbnail download.
The scrollViewDidScroll delegate method seems to be called for every pixel as you scroll which is perfect. I thought it might be too slow but so far it's not a big deal. The only issue to make sure I always check the visible cells if I sort them or something.

Resources