How do I position a subview in UIPageViewControlle

2019-06-16 06:52发布

问题:

I have a UIPageViewController subclass, and in its viewDidLoad I want to add a UILabel to its self.view. This works fine if I set its position using frames, but if I try to position it using Auto Layout, I get:

* Assertion failure in -[_UIPageViewControllerContentView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.58/UIView.m:8742

How am I supposed to position this UILabel to show up in the UIPageViewController?

回答1:

This seems to be happening because UIPageViewController's view (which is actually a _UIPageViewControllerContentView) doesn't handle subviews and autolayout as expected (at least in iOS 7; it worked fine for me in iOS 8).

You can get around this by not using autolayout, but I wanted to use autolayout so I ended up redoing my view controllers to avoid adding subviews to UIPageViewController.

Instead of subclassing UIPageViewController, I created a container view controller (a subclass of UIViewController) with a UIPageViewController as a child view controller. The custom subviews that I initially had in UIPageViewController were then added to the container's view. I also made the container the data source and delegate for the UIPageViewController.

There's a related thread where people got the same assertion failure but with a UITableViewCell: "Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass. Most of the suggestions there don't work or aren't applicable to UIPageViewController, but it helped me figure out why adding subviews with autolayout might cause a problem.



回答2:

You can also subclass UIPageViewController and implement this workaround:

#import <objc/runtime.h>

@interface MyPageViewController : UIPageViewController
@end

@implementation MyPageViewController
- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    [self applyLayoutSubviewsWorkaroundIfNeeded];
}

- (void)applyLayoutSubviewsWorkaroundIfNeeded {
    // UIPageViewController does not support AutoLayout in iOS7, we get the following runtime error
    // "_UIPageViewControllerContentView’s implementation of -layoutSubviews needs to call super…"
    // This workaround calls the missing layoutSubviews method of UIView.
    if ([self iOSVersionIsLowerThan8]) {
        IMP uiviewLayoutSubviewsImplementation = class_getMethodImplementation([self.view class], @selector(layoutSubviews));
        typedef void (*FunctionFromImplementation)(id, SEL);
        FunctionFromImplementation uiviewLayoutSubviewsFunction = (FunctionFromImplementation)uiviewLayoutSubviewsImplementation;
        uiviewLayoutSubviewsFunction(self.view, @selector(layoutSubviews));
    }
}

- (BOOL)iOSVersionIsLowerThan8 {
    // This is just one way of checking if we are on iOS7. 
    // You can use whatever method suits you best
    return ![self respondsToSelector(popoverPresentationController)];
}
@end