3

I just noted that if I put a UIScrollView as the root view of a UIViewController:

- (void)loadView
{
    self.view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
}

I get a lot of behavior for free: The scrollView sets it's contentInset and scrollIndicatorInsets automatically if the status bar, navigation bar, or toolbar are present and translucent, and updates the properties if any navigation layouts change:

[self.navigationController setNavigationBarHidden:YES animated:YES];

Unfortunately the scroll view also changes it's contentOffset automatically when changing the contentsInset, so the content goes up when the navigation bar disappears and down when the navigation bar appears.

I like a lot of this free behavior, but I would like for my content to stay still when the navigation bar comes and goes, and I can't find where to avoid the change in contentOffset.

Edit:

After some stack traces, I discovered a method that is being called every time the offset is automatically adjusted: [UIScrollView(Static) _adjustContentOffsetIfNecessary]; but since I can't find any documentation on this method, I'm at a loss.

Yamanqui
  • 199
  • 3
  • 10

3 Answers3

3

Ok, I have found it. UIViewController has a property called 'automaticallyAdjustsScrollViewInsets', which changes the contentOffset when showing/hiding navigationBar. Set it to no to prevent changes on the UIScrollView.

Source (and ios6 solution): https://stackoverflow.com/a/20325593/936957

Community
  • 1
  • 1
Yunus Nedim Mehel
  • 12,089
  • 4
  • 50
  • 56
0

My solution is add:

self.automaticallyAdjustsScrollViewInsets = NO;    

in viewDidload.

and instead of using [UINavigationController setNavigationBarHidden:animated:], I use:

self.navigationController.navigationBar.hidden = YES;//or NO   

to hide the navigationbar and avoid contentOffset change.

And remember to set the hidden state back in viewDidDisappear or some place appropriate:

self.navigationController.navigationBar.hidden = NO
wj2061
  • 6,778
  • 3
  • 36
  • 62
0

Have you tried setting the content insets when you hide/show the navigation bar?

Like this when hiding:

[self.navigationController setNavigationBarHidden:YES animated:YES];
self.view.contentInset = UIEdgeInsetsMake(self.navigationController.navigationBar.bounds.size.height, 0, 0, 0);

and this when showing:

[self.navigationController setNavigationBarHidden:NO animated:YES];
self.view.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);

AFAIK contentInset shouldn't be changed by the system, it would change the layout of your app...

jjv360
  • 4,120
  • 3
  • 23
  • 37
  • I have all the functionality working manually with the scrollView as a subview of the viewController root view; there I do manually set the `contentsInset` when showing and hiding navigation bars, and I DO NOT change the `contentOffset`, since I want my content to stay in place. What I want to know is if I can use the automatic functionality of having the scrollView as the root view, and still make my content stay in place. – Yamanqui Oct 23 '11 at 03:16
  • I don't think this is possible... The only other thing I can think of is to subclass UIScrollView and override `setContentOffset:` and only call `[super setContentOffset:offset]` if you want the document to move. By the way, all methods that start with an underscore are private APIs, and if you do anything with them, your app won't be accepted onto the App Store... – jjv360 Oct 23 '11 at 09:05