UIImageView resizing issue in UIPageViewController

2019-03-18 07:08发布

问题:

I'm building a new app and wish to have a "Welcome walkthrough" at the beginning wherein I have a storyboard with a series of images presented in a UIPageViewController. I have it loading the images and all of that just fine, however the images are resized whenever they go beyond being the "previous" or "next" ViewController. I am using Swift to develop.

Here is a video of the issue: http://youtu.be/dXcjjT-8Bk0

I have tried all of the different View Modes (Aspect fit, aspect fill, redraw etc.) and they all behave the same.

I am using Auto-Layout + Size Classes as I wish to simplify the development for different screen sizes. The current constraints I have that make the UIImage appear at the right size are:

Align Centre X  to Superview
Top Space to Top Layout Guide
Bottom Space to Bottom Layout Guide + Equals: 50

I am currently using Aspect Fit which gives me the correct image (after they have done their 'resizing behaviour'.

Can anyone guide me further as to how to fix this?

回答1:

From your video, I noticed that your UIImageView is always "resized" at the top, not at the bottom. This is most certainly because of your autolayout constraint you call "Top Space to Top Layout Guide". While your UIImageView's view controller is being transitioned through your scrolling page view controller, it doesn't know where the top layout guide is, so its topLayoutGuide.length is 0. Only after the animation completes does the view controller get a positive value for topLayoutGuide.length. Yes, the page view controller should be a bit smarter than this, but it's not.
You can either stop using the top layout guide and make an autolayout constraint relative to the top of its superview. Or you can continue to use the top layout guide but account for when it's length is 0. You can do this by making an outlet for your storyboard's NSLayoutConstraint and overriding viewWillLayoutSubviews() in your ViewController containing your UIImageViews:

@IBOutlet weak var topSpaceToTLG: NSLayoutConstraint!
var parentTLGlength: CGFloat = 20

override func viewWillLayoutSubviews() {
    if self.topLayoutGuide.length == 0 {
        // Lengthen the autolayout constraint to where we know the 
        // top layout guide will be when the transition completes
        topSpaceToTLG.constant = parentTLGlength
    } else {
        topSpaceToTLG.constant = 0
    }
}

This will always put the top of your UIImageView at the top layout guide, assuming that the status bar is always 20 points. Before laying out subviews, it will check to see if the top layout guide length is 0 or not and adjusts your autolayout constraint accordingly. After the transition animation completes, layout is triggered again, and the top layout guide length will be the expected value, so the constraint constant can go back to 0. Even better than hardcoding the value is to pass in the parent view controller's exact length during initialization, accounting for any possible changes to the top layout guide like adding a navigation bar.



回答2:

From the video I think you could solve this by preventing the UIPageViewController from extending under the top bars.

In xcode you can do this using the attribute inspector for the page view controller by deselecting Extend Edges Under Top Bars.

This should prevent it paging in under the status bar I think helping to avoid the switch you see.



回答3:

I figured out my problem was that when the view controller began animating the Top and Bottom Layout Guides had no height. The right and left margins didn't either. When the view finished animating they all received a height or width and my view resized itself. I fixed this problem on my project by adding vertical constraints between my objects and their super view instead of to the Top/Bottom Layout Guide. I also had to change my horizontal constraints to ignore the side margins.

The last issue I came across is that I had to account for the status bar myself. It may or may not be there or it could be a double bar, like when you are using Maps.