19

I have a UIImageView embedded inside a UIScrollView, prior to iOS 6 and autolayout I used the following snippet inside the controller's viedDidLoad method to display a scrollable and zoomable image.

self.scrollView.contentSize = self.imageView.image.size;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);

But now the constraints set in the storyboard are used instead. I've found this question Embed ImageView in ScrollView with Auto Layout on iOS 6 and some others here in SO stating that constraints are loaded/enforced after viewDidLoad, and that moving my previous snippet to viewDidAppear would fix this issue but zooming does not work properly and it seems that the sizes of the scrollView and the imageView are reset to the storyboard's constraint after a pinch-to-zoom gesture.

I'm just guessing, but I think maybe if there's some way to override the scrollView's and imageView's vertical and horizontal space constraints in code that might work.

Anyone else having this issues?

O'Neil
  • 3,790
  • 4
  • 16
  • 30
Diego Allen
  • 4,623
  • 5
  • 30
  • 33

3 Answers3

14

The best solution was proposed by Zsolt in the comments:

http://github.com/evgenyneu/ios-imagescroll check this out. Works perfectly for me.

The solution proposed in this repository is to adjust the minimum and current zoom level before displaying the image:

    @interface MyViewController () <UIScrollViewDelegate>
    @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @end


    @implementation MyViewController

    - (void)viewDidLoad
    {
      [super viewDidLoad];
      self.scrollView.delegate = self;
      
      [self initZoom];
    }
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
      [self initZoom];
    }

    // Zoom to show as much image as possible
    - (void) initZoom {
      float minZoom = MIN(self.view.bounds.size.width / self.imageView.image.size.width,
                          self.view.bounds.size.height / self.imageView.image.size.height);
      if (minZoom > 1) return;
      
      self.scrollView.minimumZoomScale = minZoom;
      
      self.scrollView.zoomScale = minZoom;
    }

    - (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
      return self.imageView;
    }

However sample conatins issue with zooming out. Image is not getting centered. This can be easily fixed by using the custom scroll view class with the following code in it:

    @interface MyScrollView : UIScrollView
    @end

    @implementation MyScrollView

    -(void)layoutSubviews
    {
      [super layoutSubviews];
      UIView* v = [self.delegate viewForZoomingInScrollView:self];
      CGFloat svw = self.bounds.size.width;
      CGFloat svh = self.bounds.size.height;
      CGFloat vw = v.frame.size.width;
      CGFloat vh = v.frame.size.height;
      CGRect f = v.frame;
      if (vw < svw)
        f.origin.x = (svw - vw) / 2.0;
      else
        f.origin.x = 0;
      if (vh < svh)
        f.origin.y = (svh - vh) / 2.0;
      else
        f.origin.y = 0;
      v.frame = f;
    }

    @end
O'Neil
  • 3,790
  • 4
  • 16
  • 30
Anton Matosov
  • 1,685
  • 1
  • 20
  • 19
  • Just FYI the project link you gave is outdated and has been updated in Swift = https://github.com/evgenyneu/ios-imagescroll-swift – Daniel Galasko Jan 08 '15 at 11:54
7

Solved my problem using the following code sample. The github repository corresponds to the book Programming iOS by Matt Neuburg.

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/11c6c57743b04e6e722b635b87be69fa41a5abaf/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m

pix0r
  • 31,139
  • 18
  • 86
  • 102
Diego Allen
  • 4,623
  • 5
  • 30
  • 33
  • This is better, but when I zoom out my image is centered on the top-left corner rather than the center of the scroll view (or rather than having the corner of the image at the origin). Also note that the example has a IBOutletCollection for constraints that must include ALL the constraints on the UIImageView or you'll get an exception when zooming. – webjprgm Feb 07 '13 at 03:57
  • 2
    I fixed my problem by turning off translatesAutoresizingMaskIntoConstraints and then setting the frame's origin to 0,0 in viewWillLayoutSubviews. The image is not centered, but at least it doesn't slide off the scrollable area when zooming anymore. – webjprgm Feb 19 '13 at 01:20
  • I used [_imgProduct setCenter:_scrProduct.center]; instead of the 0,0 and translatesAutoresizingMaskIntoConstraints = NO; – Zsolt Jun 15 '13 at 07:30
  • 12
    https://github.com/evgenyneu/ios-imagescroll check this out. Works perfectly for me. – Zsolt Jun 15 '13 at 07:57
5

I also agree with Zsolt's suggestion and link.

But I update the width/height constraints to allow it to handle any size image:

- (void) initZoom
{
    for (NSLayoutConstraint *constraint in self.photoImageView.constraints)
    {
      if (constraint.firstAttribute == NSLayoutAttributeWidth)
        constraint.constant = self.photoImageView.image.size.width;
      else if (constraint.firstAttribute == NSLayoutAttributeHeight)
        constraint.constant = self.photoImageView.image.size.height;
    }
    
    float minZoom = MIN(self.scrollView.bounds.size.width / self.photoImageView.image.size.width,
                        self.scrollView.bounds.size.height / self.photoImageView.image.size.height);
    if (minZoom > 1) return;

    self.scrollView.minimumZoomScale = minZoom;
    
    self.scrollView.zoomScale = minZoom;
}
TylerJames
  • 941
  • 8
  • 27
Mof
  • 363
  • 3
  • 9