UIImageView and UIScrollView zooming

43,797

Solution 1

All you need to do is add your UIImageView (or any view you want to zoom) inside your UIScrollView.

Set your maximumZoomScale on your UIScrollView to any value higher than 1.0f.

Set yourself as the delegate of your UIScrollView and return the UIImageView in the viewForZooming delegate method.

That's it. No pinch gesture needed, no nothing. UIScrollView handles pinch zooming for you.

Solution 2

Objective C

Pinch-zoom Image in Scrollview Steps (Objective C)

1. Scroll View Constraints

enter image description here

2. Add ImageView In ScrollView and set Constraints

enter image description here

3. Take IBOutlets

IBOutlet UIScrollView * bgScrollView;
IBOutlet UIImageView * imageViewOutlet;

4. viewDidLoad Method

- (void)viewDidLoad
 {
    [super viewDidLoad];

    float minScale=bgScrollView.frame.size.width / imageViewOutlet.frame.size.width;
    bgScrollView.minimumZoomScale = minScale;
    bgScrollView.maximumZoomScale = 3.0;
    bgScrollView.contentSize = imageViewOutlet.frame.size;
    bgScrollView.delegate = self;
}

5. Scroll View Delegate Method

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return imageViewOutlet;
}

Swift

Pinch-zoom Image in Scrollview Steps (Swift)

1. Scroll View Constraints

enter image description here

2. Add ImageView In ScrollView and set Constraints

enter image description here

3. Take IBOutlets

@IBOutlet weak var bgScrollView : UIScrollView!
@IBOutlet weak var imageView : UIImageView!

4. viewDidLoad Method

 override func viewDidLoad() {
    super.viewDidLoad()

    let minScale = bgScrollView.frame.size.width / imageView.frame.size.width;
    bgScrollView.minimumZoomScale = minScale
    bgScrollView.maximumZoomScale = 3.0
    bgScrollView.contentSize = imageView.frame.size
    bgScrollView.delegate = self
}

5. Scroll View Delegate Method

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return imageView
}

Solution 3

I did a custom image viewer not a long ago without the pinch recognizers. Just UIImageView on top of UIScrollView. There you pass a string with a link to the image and it also has a progress bar. Once that image is finished loading the image is shown. Here's the code:

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

- (CGRect)centeredFrameForScrollView:(UIScrollView *)scroll andUIView:(UIView *)rView {
  CGSize boundsSize = scroll.bounds.size;
  CGRect frameToCenter = rView.frame;
  // center horizontally
  if (frameToCenter.size.width < boundsSize.width) {
    frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
  }
  else {
    frameToCenter.origin.x = 0;
  }
  // center vertically
  if (frameToCenter.size.height < boundsSize.height) {
    frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
  }
  else {
    frameToCenter.origin.y = 0;
  }
  return frameToCenter;
}

-(void)scrollViewDidZoom:(UIScrollView *)scrollView
{
  self.theImageView.frame = [self centeredFrameForScrollView:self.theScrollView andUIView:self.theImageView];                               
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
  [self.resourceData setLength:0];
  self.filesize = [NSNumber numberWithLongLong:[response expectedContentLength]];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
  [self.resourceData appendData:data];
  NSNumber *resourceLength = [NSNumber numberWithUnsignedInteger:[self.resourceData length]];
  self.progressBar.progress = [resourceLength floatValue] / [self.filesize floatValue];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  self.theImage = [[UIImage alloc]initWithData:resourceData];
  self.theImageView.frame = CGRectMake(0, 0, self.theImage.size.width, self.theImage.size.height);
  self.theImageView.image = self.theImage;
  self.theScrollView.minimumZoomScale = self.theScrollView.frame.size.width / self.theImageView.frame.size.width;
  self.theScrollView.maximumZoomScale = 2.0;
  [self.theScrollView setZoomScale:self.theScrollView.minimumZoomScale];
  self.theScrollView.contentSize = self.theImageView.frame.size;
  self.theLabel.hidden = YES;
  self.progressBar.hidden = YES;
}

-(void)setImageInImageView
{
  NSURLRequest *req = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:self.imageLink]];
  NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:req delegate:self];
  if (conn)
  {
    self.resourceData = [NSMutableData data];
  }
  else
  {
    NSLog(@"Connection failed: IMageViewerViewController");
  }
}

-(void)loadView
{
  self.filesize = [[NSNumber alloc]init];
  self.progressBar = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleBar];
  self.progressBar.frame = CGRectMake(20, 240, 280, 40);
  [self.progressBar setProgress:0.0];
  self.theImageView = [[[UIImageView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame]]autorelease];
  self.theScrollView = [[[UIScrollView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame]]autorelease];
  self.theScrollView.delegate = self;
  [self.theScrollView addSubview:self.theImageView];
  self.view = self.theScrollView;
  self.theLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 200, 320, 40)];
  self.theLabel.font = [UIFont boldSystemFontOfSize:15.0f];
  self.theLabel.text = @"Please wait, file is being downloaded";
  self.theLabel.textAlignment = UITextAlignmentCenter;
  self.theLabel.hidden = NO;
  [self.view addSubview:self.progressBar];
  [self.view bringSubviewToFront:self.progressBar];
  [self.view addSubview:self.theLabel];
  [self.view bringSubviewToFront:self.    theLabel];
  [self performSelectorOnMainThread:@selector(setImageInImageView) withObject:nil waitUntilDone:NO];
}

And the header file:

@interface ImageViewerViewController : UIViewController<UIScrollViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate>

@property (nonatomic, retain) IBOutlet UIImageView *theImageView;
@property (nonatomic, retain) IBOutlet UIScrollView *theScrollView;
@property (nonatomic, retain) NSString *imageLink;
@property (nonatomic, retain) UIImage *theImage;
@property (nonatomic, retain) UILabel *theLabel;
@property (nonatomic, retain) UIProgressView *progressBar;
@property (nonatomic, retain) NSMutableData *resourceData;
@property (nonatomic, retain) NSNumber *filesize;
@end

Hope it helps

Solution 4

I guess this answer may be unnecessary but I have had similar problems as @adit and solved it in a very simple way (I think) and maybe someone with similar challenges can use it:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor yellowColor];

    UIImage *imageToLoad = [UIImage imageNamed:@"background_green"];

    self.myImageView = [[UIImageView alloc]initWithImage:imageToLoad];
    self.myScrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
    [self.myScrollView addSubview:self.myImageView];
    self.myScrollView.contentSize = self.myImageView.bounds.size;
    self.myScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    self.myScrollView.minimumZoomScale = 0.3f;
    self.myScrollView.maximumZoomScale = 3.0f;
    self.myScrollView.delegate = self;
    [self.view addSubview:self.myScrollView];
}

- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView {
    NSLog(@"viewForZoomingInScrollView");
    return self.myImageView;
} 

My problem was a very simple I had forgot to add self.myScrollView.delegate = self;, which was the reason why i had problems. It took me forever to figure that simple problem out, i guess I did not see the forrest for all the trees :-)

Solution 5

When I was developing my Zooming PDF viewer in a UIScrollView I found out that when running it on the Phone it actually already has the zooming implemented as part of the phone. But you could have a look at this, http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html it is a piece of sample code that tries to implement the functionality for zooming, this is want got me started.

Share:
43,797
adit
Author by

adit

Updated on July 02, 2020

Comments

  • adit
    adit almost 4 years

    Do I actually need a UIPinchGestureRecognizer inside a UIScrollView to have the pinch working? If yes how do I do it? I am trying to implement what flipboard has, where it basically zooms in an image and have the scroll capability after zooming in. How do I do that?

    UPDATE:

    Here's some code that I have which doesn't call the scroll view delegate

    CGRect imgFrame;
    imgFrame.size.width = originalImageSize.width;
    imgFrame.size.height = originalImageSize.height;
    imgFrame.origin.x = imageOriginPoint.x;
    imgFrame.origin.y = imageOriginPoint.y;
    
    NSData *data = [request responseData];
    UIImage * image = [UIImage imageWithData:data];
    imageView = [[UIImageView alloc] initWithImage:image];
    [imageView setUserInteractionEnabled:YES];
    [imageView setBackgroundColor:[UIColor clearColor]];
    [imageView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
    [imageView setFrame:CGRectMake(0, 0, imgFrame.size.width, imgFrame.size.height)];
    
    UIScrollView * imgScrollView = [[UIScrollView alloc] initWithFrame:imageView.frame];
    imgScrollView.delegate = self;
    imgScrollView.showsVerticalScrollIndicator = NO;
    imgScrollView.showsHorizontalScrollIndicator = NO;
    [imgScrollView setScrollEnabled:YES];
    [imgScrollView setClipsToBounds:YES];
    [imgScrollView addSubview:imageView];
    [imgScrollView setBackgroundColor:[UIColor blueColor]];
    [imgScrollView setMaximumZoomScale:1.0];