b2cloud

15th January 2014

Calculate iOS7 view insets

Guides | Tutorial By 3 years ago

Update: This is now available on GitHub, along with Unit Tests and updated for the bottom layout guide
https://github.com/tparry/UIViewController-Insets

In iOS7 a view controller now positions it’s view from the top of itself compared to previously starting below the navigation bar. If you use a single scroll view you can set automaticallyAdjustsScrollViewInsets to YES to automatically handle things for you, however if your UI is more complicated then you may need to do things manually. The view controller has a topLayoutGuide property which is useful in some cases, but unfortunately doesn’t take parent view controllers into consideration, or the view’s origin inside the view controller.

Take the following example of a view controller inside a navigation controller with two UIScrollViews. The left scroll view sits all the way up to the top of the screen, however the right scroll view sits half way between the navigation bar. The left one can simply use the topLayoutGuide to be given a contentInset.top of 64. The scroll view on the right needs to have some trickier logic, the topLayoutGuide minus the origin.y of the scroll view (22).

 

If instead our scroll view is in a child view controller (UINavigationController -> UIViewController -> child UIViewController) then we would need to know to query the parent view controller’s topLayoutGuide, and also take our own view’s position into consideration, as well as the scroll view and navigation bar.

I built a method a while back that does just this, it works on parent view controllers, child view controllers, custom frame view controllers, popover view controllers, and any other configuration you can think of.

@implementation UIViewController (Insets)

- (UIEdgeInsets) insetsForView:(UIView*) view
{
	UIViewController* viewController = self;
	
	//	Until root or a navigation controller
	if(![viewController isKindOfClass:[UINavigationController class]])
	{
		while(viewController.parentViewController != nil && ![viewController.parentViewController isKindOfClass:[UINavigationController class]])
			viewController = viewController.parentViewController;
	}
	
	const CGPoint convertedOrigin = [viewController.view convertPoint:view.bounds.origin fromView:view];
	
	const CGFloat topLayoutGuideLength = (([viewController respondsToSelector:@selector(topLayoutGuide)]) ? [viewController.topLayoutGuide length] : 0);
	
	const UIEdgeInsets rawInsets = UIEdgeInsetsMake(topLayoutGuideLength - convertedOrigin.y, 0, 0, 0);
	
	return UIEdgeInsetsMake(MAX(0, rawInsets.top) + ABS(MIN(0, self.view.frame.origin.y + convertedOrigin.y)),
							MAX(0, rawInsets.left),
							MAX(0, rawInsets.bottom),
							MAX(0, rawInsets.right));
}

@end

So now I can write:

@implementation CustomViewController

- (void) viewWillLayoutSubviews
{
	[super viewWillLayoutSubviews];
	
	const UIEdgeInsets insets = [self insetsForView:self.scrollView];
	[self.scrollView setContentInset:insets];
}

@end
Recommended Posts

Yammer integrations in ReactJS

Post by 3 years ago

I am writing this blog while I am working on a project for our client’s intranet website. The client requires the website has the ability to share, like and write comments in the website through

Got an idea?

We help entrepreneurs, organizations and established brands from around
the country bring ideas to life. We would love to hear from you!