Consider a UIScrollView
with a single subview. The subview is an UIImageView
with the following size constraints:
UIScrollView
.UIImageView
.It is expected that the width of the UIImageView
will be bigger than the width of the UIScrollView, hence the need for scrolling.
The image might be set during viewDidLoad
(if cached) or asynchronously.
How do you implement the above using autolayout, making as much use as possible of Interface builder?
Based on this answer I configured my nib like this:
UIScrollView
is pinned to the edges of its superview.UIImageView
is pinned to the edges of the UIScrollView
.UIImageView
has a placeholder intrinsic size (to avoid the Scrollable Content Size Ambiguity error)As expected, the result is that the UIImageView
is sized to the size of the UIImage
, and the UIScrollView
scrolls horizontally and vertically (as the image is bigger than the UIScrollView
).
Then I tried various things which didn't work:
UIImageView
.zoomScale
after the image is loaded. Has no visible effect.The following code does exactly as I want, albeit without autolayout or interface builder.
- (void)viewDidLoad
{
{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:scrollView];
self.scrollView = scrollView;
}
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.scrollView addSubview:imageView];
self.scrollView.contentSize = imageView.frame.size;
self.imageView = imageView;
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self layoutStripImageView];
}
- (void)layoutStripImageView
{ // Also called when the image finishes loading
UIImage *image = self.imageView.image;
if (! image) return;
const CGSize imageSize = image.size;
const CGFloat vh = self.scrollView.frame.size.height;
const CGFloat scale = vh / imageSize.height;
const CGFloat vw = imageSize.width * scale;
CGSize imageViewSize = CGSizeMake(vw, vh);
self.imageView.frame = CGRectMake(0, 0, imageViewSize.width, imageViewSize.height);
self.scrollView.contentSize = imageViewSize;
}
I'm trying really hard to move to autolayout but it's not being easy.
In my case it was a full width UIImageView the had a defined height constraint that causing the problem.
I set another constraint on the UIImageView for the width that matched the width of the UIScrollView as it is in interface builder then added an outlet to the UIViewController:
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *imageViewWidthConstraint;
then on viewDidLayoutSubviews I updated the constraint:
- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.imageViewWidthConstraint.constant = CGRectGetWidth(self.scrollView.frame);
}
This seemed to do the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With