UIScrollView Zoom Does Not Work With Autolayout UIScrollView Zoom Does Not Work With Autolayout ios ios

UIScrollView Zoom Does Not Work With Autolayout


Once again, re-reading the iOS SDK 6.0 release notes I found that:

Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints between the view and a view outside the scroll view’s subtree, such as the scroll view’s superview.

Solution

Connect your subview to the outer view. In another words, to the view in which scrollview is embedded.

And applying constraints in following way I've got it work:

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView(width)]" options:0 metrics:@{@"width":@(self.imageViewPointer.image.size.width)} views:viewsDictionary]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(height)]" options:0 metrics:@{@"height":@(self.imageViewPointer.image.size.height)} views:viewsDictionary]];


The issues that occurs is the changing of location of the imageview during the zoom process. The origin location of the imageview will change to be a negative value during the zoom. I believe this is why the jerky movement occurs. As well, after the zoom is complete the imageView is still in the wrong location meaning that scrolls will appear to be offset.

If you implement -(void) scrollViewDidZoom:(UIScrollView *)scrollView and log the frame of the UIImageView during this time you can see its origin changing.

I ended up making things work out by implementing a strategy like this

And in addition changing the frame of the contentView while zooming

-(void) scrollViewDidZoom:(UIScrollView *)scrollView {    CGRect cFrame = self.contentView.frame;    cFrame.origin = CGPointZero;    self.contentView.frame = cFrame;}


These solutions all kinda work. Here is what I did, no hacks or subclasses required, with this setup:

[view]  [scrollView]    [container]      [imageView]      [imageView2]
  1. In IB, hook up top, leading, bottom and trailing of scrollView to view.
  2. Hook up top, leading, bottom and trailing of container to scrollView.
  3. Hook up center-x and center-y of container to center-x and center-y of scrollView and mark it as remove on build time. This is only needed to silence the warnings in IB.
  4. Implement viewForZoomingInScrollView: in the view controller, which should be scrollView's delegate, and from that method return container.
  5. When setting the imageView's image, determine minimum zoom scale (as right now it will be displayed at the native size) and set it:

    CGSize mySize = self.view.bounds.size;CGSize imgSize = _imageView.image.size;CGFloat scale = fminf(mySize.width / imgSize.width,                      mySize.height / imgSize.height);_scrollView.minimumZoomScale = scale;_scrollView.zoomScale = scale;_scrollView.maximumZoomScale = 4 * scale;

This works for me, upon setting the image zooms the scroll view to show the entire image and allows to zoom in to 4x the initial size.