UIScrollView stops scrolling when another view loads and dismisses - ios

I have a UIScrollView and another UIView (view2) inside it. 'view2' scrolls fine when app launches. But, whenever I show and dismisses another VC (a UIImagePickerControler in this case) scrollView becomes non scrollable.
I have set the content size at viewDidAppear , so this must be something related to AutoLayout constraints. I've tested with all the constraints removed but still getting the same result.
Any idea why is this happening?

Not a complete answer, but make sure your viewDidAppear: method doesn't assume it's only called once. It will be called again when the second view controller is dismissed.

Related

UICollectionView moves super view when calling cellForRowAtIndexPath

I have a view that is placed outside the screens bounds (beneath). When a button is pushed this view is animated up, so that it becomes visible. It sort of acts like a keyboard, although it isnĀ“t.
Inside this view I have a container view which is hooked up to a UICollectionViewController.
The problems occurs when I scroll its collectionView. As soon as cellForRowAtIndexPath is called, the entire super view is moved outside the screen again (without animation). If I push the button again it animates back up.
Does anyone know what is causing this behavior? I suspect that the frames of the reused cells are sort of pushing the super view back to where it was initialized. Any suggestions how I should resolve this?
When using autolayout, you should animate using constraints. I had this same issue before. Maybe viewDidLayoutSubviews is called multiple times while you are using the app, and hides your view again.

Tapping status bar doesn't scroll table view to top

Ok, I've read almost every single post about this issue, and they all say the same thing:
In the whole view hierarchy, only one scroll view (or subclass) should have scrollsToTop set to YES and the rest should be NO. When my view loads, I recursively iterate the whole view hierarchy just as many answers suggest, setting scrollsToTop to NO, then I only set my table view's scrollsToTop to YES, but still, it doesn't scroll when I tap the status bar. I've overridden:
-(BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView{
return YES;
}
But it's not even called even though my view controller is the scroll view delegate of my table view.
I do have cells with text views, and when the container cell awakes from nib, I also set their scrollsToTop property to NO immediately, and there are no other views deriving from scroll view.
Why would it not work?
For what it's worth, I've never set scrollsToTop on any table view controller I've ever used, and they all do this by default. Maybe all this recursive view hierarchy stuff is what is actually causing the problem. I just looked at all the apps I've written, and all of them work fine without ever touching scrollsToTop, and many of them have embedded scrollViews/textViews/etc in them. Perhaps try commenting out all that scrollsToTop code and trying it then?
Otherwise, how are you building this tableview? Is it with a nib or is this a normal UITableViewController?

Unresponsive UIScrollView after dismiss modal view

This issue is driving me crazy.
I have a UIScrollView with a content view that doubles its size. Scroll is enabled and contentSize is set. The content view has a pair of UICollectionView side by side so you can scroll the view between both of them (scroll paging is enabled too). Everything works ok until I select a cell. The app presents a modal with some info and, when I dismiss the modalview, the scrollView becomes unresponsive and doesn't scroll (but I still can select the collectionView cells!). It even change the contentOffset with animation to the proper "page" but doesn't scroll at all when dragging.
It sounds like the good old contenSize error but when I log the sizes in viewDidAppear, it has the right size.
FYI: I'm targeting iOS7 and I set the scrollview layout using storyboard with AutoLayout.
Any help will be appreciated
Solved. It seems that the constraints I set in storyboard weren't recreated when the modal was dismissed (I don't know why). Creating the layout by code did the trick.

How to scroll a UIScrollView on load when using auto layout

I have a UIScrollView that is set up in the viewDidLoad method of a UIViewController (I'll call it a ScrollViewController). The scroll view contains pages of horizontal content (similar to the native weather app).
When displaying the scrollview, it should be possible to choose which page it starts on. My pattern is this:
init a ScrollViewController. Nothing much happens in here. A currentPage property is defaulted to 0.
set the scrollViewController.currentPage to the desired page number.
in viewDidLoad of ScrollViewController, read self.currentPage and use scrollToRect or setContentOffset to scroll accordingly.
The scrolling implementation seems fine, since I am using the same code elsewhere to jump to certain pages. But on first load, nothing happens (that is, the scroll view is not scrolled to the desired page).
I think I have found the reason - it seems that the contentSize of the scroll view (which is derived by autolayout remember) is 0 during viewDidLoad, and this seems that this prevents scrolling. It is also zero during viewWillAppear. Only in viewDidAppear does the scroll work, which of course makes for an odd user experience.
How can I resolve this? Is it wise to somehow force a layout in viewDidLoad? Or some other approach?
viewDidLayoutSubviews is what you are looking for. This is the method where all the subviews frames are completly initialized. So, try to call your scrollView's setup method inside it, in your viewController:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self setupView];
}
You should be able to set content size manually. Where do you insert the pages inside the scroll view? I would suggest inserting them inside viewDidLoad or viewWillAppear and then scrolling to the desired page just after inserting them by setting its contentOffset.

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.

Resources