19
votes

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?

3

3 Answers

14
votes

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
7
votes
5
votes

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;
}