UIPageViewController in UINavigationController only updates autolayout constraints for top layout guide in viewDidAppear (or similar)

Originator:openradar
Number:rdar://21728584 Date Originated:08-Jul-2015 08:34 PM
Status:Open Resolved:
Product:iOS SDK Product Version:8.4 & iOS 9.0
Classification:UI/Usability Reproducible:Always
 
Summary:
When A UIPageViewController is used inside a UINavigationController constraints in the managed view controllers related to the top layout guide are setup/updated to late. They should be update in viewWillAppear, before any part of the shown pages  is first displayed. Instead the constraints are only updated on what appear to be viewDidAppear: or a similar method. At least, the constraints are only correct after the page view controller’s animation finished, not during the animation of a newly loaded child view controller.

Steps to Reproduce:
1. Create a UINavigationViewController with s simple UIViewController als root view controller
2. Create a UIPageViewController with transitionStyle UIPageViewControllerTransitionStyleScroll (it also happens for PageCurl, but only when paging backwards. It happens for scrolling in both directions)
3. Add the page view controllers view as a (full screen) subview to the root view controllers view.
4. Assign a datasource to the UIPageViewController that returns simple UIViewController objects to display (at least 4 different ones).
5. Make the datasource return UIViewController objects with views that contain subviews with an auto layout constraint related to the TopLayoutGuide (e.g. a label that has a 10pt distance from the top layout guide).

Expected Results:
As soon as you start scrolling to the next child view controller in the page view controller the next view controller should be shown partially and the layout of the partially displayed view controller should already be correct.

Actual Results:
The layout of the partially displayed view controller is incorrect. It behaves as if the top layout guide for this view controller is at the top of the screen, but it the top layout guide should be at the bottom of the navigation bar. (see screenshot)

Regression:
The problem does not occur if the view controller that is moved in was already loaded and had the constraint calculated correctly at least once. This is the case when e.g. navigating from page 1 to page 2 in the page view controller and then going back to page 1 (using transition style UIPageViewControllerTransitionStyleScroll). As page 1 is still in memory, it is displayed correctly when being animated in.
The problem also does not occur when UIPageViewControllerTransitionStylePageCurl is used and the navigation direction is forwards. It DOES occur when navigation backwards.

Notes:
Attached a a sample project. This is based on apples „Page-Based Application“ project tempalte. The only changes to this template are:
1. Changes the transition style to UIPageViewControllerTransitionStyleScroll to make the problem more visible
2. Put the UIPageViewController inside a navigation controller
3. Adjust the top constraints of the month label in the child view controller to relate to the top layout guide instead of superview.top.

Comments

Seems to be fixed for UIPageViewControllerTransitionStyleScroll in iOS 9.0, still an issues in iOS 8.4 and also with UIPageViewControllerTransitionStylePageCurl in iOS 9.0 (paging backwards)


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!