I'm building a complicated project where, among other things, I need to set a UIPageViewController as a childview of a main view. I'm using autolayout, and using constraints to order the various elements on the main view.
The problem is, that when I try to run the app, it crashes due to conflicting NSAutoresizingMaskLayoutConstraints.
2013-10-28 16:22:18.419 Red Event App[1658:60b] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x145c1990 V:|-(20)-[UINavigationBar:0x145bf6b0] (Names: '|':UIView:0x145bf620 )>",
"<NSLayoutConstraint:0x145bf510 V:[UINavigationBar:0x145bf6b0]-(0)-[UIView:0x145bef70]>",
"<NSLayoutConstraint:0x145d0550 UIView:0x145a8c10.top == UIView:0x145bf620.top>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a40 h=-&- v=-&- UIView:0x145a8c10.midY == UIView:0x145bef70.midY + 56.5>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a70 h=-&- v=-&- UIView:0x145a8c10.height == UIView:0x145bef70.height + 113>"
)
The usual cure for this is setting TranslatesAutoresizingMaskIntoConstraints to no.
However, when I do this the child views of the UIPageViewController start to ignore the bounds of the PageViewController, and end up (as far as I can see) with an origin of (0,0).
I've tried to fix the position by setting the frames by hand both when setting up the datasource (_itemViewControllers):
- (void)setupLeafs{
_itemViewControllers = [[NSMutableArray alloc]init];
for(NSString *pagename in _datasource){
RWNode *page = [_xml getPage:pagename];
UIViewController *viewController = [RWNavigationController getViewControllerFromDictionary:[page getDictionaryFromNode]];
viewController.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.width, self.view.frame.size.height);
[_itemViewControllers addObject:viewController];
}
}
and when getting the page
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
UIViewController *nextViewController = [self getPreviousLeaf:viewController];
nextViewController.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.width, self.view.frame.size.height);
return nextViewController;
}
but neither have any effect.
I need the constraints for what I'm doing, so sticking to Masks is not an option. I think what I'm looking for is a way to put constraints on the UIPageViewController children after they've been added (by whatever process calls viewControllerBeforeViewController
). But I'd really like to hear about any way that this problem can be solved.
Edit: I have found a hack to solve the problem. I'm not quite sure if what I'm listing here is the entire solution, but it is what I notice right now, after more than a month of tinkering with the code.
First, in the view controller that sets up the pageviewcontroller, I have the following two lines, after I've initialized the pageviewcontroller
UIView *pageView = self.pageViewController.view;
pageView.frame = self.view.frame;
Not that I have set [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
in this view controller.
Secondly, on the child controllers I check whether the view is being used inside or outside of a pageviewcontroller. Only if the view is not being used in a pageviewcontroller is [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
set on the child view.
Now, this works (for me) at the moment. But I would really like a solution that is less hacky.
When using AutoLayout, you should never directly set the frame of a view. Constraints are used to do this for you. Normally if you want to set your own constraints in a view, you override the updateConstraints
method of your UIViews. Make sure the content views for the page controller allow for their edges to be resized since they will be sized to fit the page view's frame. Your constraints and view setup will need to account for this, or you you will get unsatisfiable constraint errors.