Search code examples
iosios6uiviewuiscrollviewuiimageview

Reset UIScrollView to new frame dimensions after orientation change


I have an ImageZoom class that subclasses UIView and is a delgate for the UIScrollView. It's pretty straight forward. The class contains a UIScrollView which contains a UIImageView. When an instance of the class is added to a view controller the image is zoomed so that it is flush with the view. There is a method that zooms in when you double tap and zooms out when repeated. Everything works great except for when I change orientation to landscape. I can't seem to figure out how to get the zoom right so that the image is now flush with the new orientation. Here is a link to file as well:

http://www.2shared.com/file/bowDjzLr/imagescroll.html

ViewController.h

#import <UIKit/UIKit.h>
#import "ImageZoom.h"

@interface ViewController : UIViewController

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) ImageZoom *imageZoom;
@property (nonatomic, strong) UIImage *image;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.image = [UIImage imageNamed:@"1.png"];
}

-(void)viewDidAppear:(BOOL)animated
{
    ImageZoom *imageZoom = [[ImageZoom alloc]initWithImage:self.image andFrame:self.view.bounds];
    self.imageZoom = imageZoom;
    [self.view addSubview:imageZoom];

}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [self.imageZoom willAnimateToFrame:self.view.bounds];
}

@end

ImageZoom.h

#import <UIKit/UIKit.h>

@interface ImageZoom : UIView <UIScrollViewDelegate>

- (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame;
-(void)willAnimateToFrame:(CGRect)frame;

@end

ImageZoom.m

#import "ImageZoom.h"

@interface ImageZoom ()

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property BOOL zoomed;

@end

@implementation ImageZoom

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self loadContent];
    }
    return self;
}
-(void)loadContent
{
    self.scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.scrollView.delegate = self;
    self.scrollView.contentSize = self.image.size;
    [self.scrollView addSubview:self.imageView];
    [self addSubview:self.scrollView];

    CGRect scrollViewFrame = self.scrollView.frame;
    CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
    CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
    CGFloat minScale = MIN(scaleWidth, scaleHeight);

    self.scrollView.minimumZoomScale = minScale;
    self.scrollView.maximumZoomScale = 1;
    self.scrollView.zoomScale = minScale;

    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollViewDoubleTapped:)];
    doubleTapRecognizer.numberOfTapsRequired = 2;
    doubleTapRecognizer.numberOfTouchesRequired = 1;
    [self.scrollView addGestureRecognizer:doubleTapRecognizer];
}

-(void)willAnimateToFrame:(CGRect)frame
{
    self.scrollView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);

    CGRect scrollViewFrame = self.scrollView.frame;
    CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
    CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
    CGFloat minScale = MIN(scaleWidth, scaleHeight);

    self.scrollView.minimumZoomScale = minScale;
    self.scrollView.maximumZoomScale = 1;
    self.scrollView.zoomScale = minScale;

    CGPoint centerPoint = CGPointMake(CGRectGetMidX(self.scrollView.frame), CGRectGetMidY(self.scrollView.frame));
    [self view:self.imageView setCenter:centerPoint];
}


- (void)view:(UIView*)view setCenter:(CGPoint)centerPoint
{
    CGRect viewFrame = view.frame;

    CGPoint scrollViewContentOffset = self.scrollView.contentOffset;

    CGFloat x = centerPoint.x - viewFrame.size.width / 2.0;
    CGFloat y = centerPoint.y - viewFrame.size.height / 2.0;

    if(x < 0)
    {
        scrollViewContentOffset.x = -x;
        viewFrame.origin.x = 0.0;
    }
    else
    {
        viewFrame.origin.x = x;
    }
    if(y < 0)
    {
        scrollViewContentOffset.y = -y;
        viewFrame.origin.y = 0.0;
    }
    else
    {
        viewFrame.origin.y = y;
    }

    view.frame = viewFrame;
    self.scrollView.contentOffset = scrollViewContentOffset;
    self.zoomed = NO;
}

- (id)initWithImageView:(UIImageView *)imageView andFrame:(CGRect)frame
{
    self.image = imageView.image;
    self.imageView = imageView;
    return [self initWithFrame:frame];
}

- (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame
{
    self.image = image;
    self.imageView = [[UIImageView alloc] initWithImage:self.image];
    return [self initWithFrame:frame];
}

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

- (void)scrollViewDidZoom:(UIScrollView *)sv
{
    UIView* zoomView = [sv.delegate viewForZoomingInScrollView:sv];
    CGRect zoomViewFrame = zoomView.frame;
    if(zoomViewFrame.size.width < sv.bounds.size.width)
    {
        zoomViewFrame.origin.x = (sv.bounds.size.width - zoomViewFrame.size.width) / 2.0;
    }
    else
    {
        zoomViewFrame.origin.x = 0.0;
    }
    if(zoomViewFrame.size.height < sv.bounds.size.height)
    {
        zoomViewFrame.origin.y = (sv.bounds.size.height - zoomViewFrame.size.height) / 2.0;
    }
    else
    {
        zoomViewFrame.origin.y = 0.0;
    }
    zoomView.frame = zoomViewFrame;
}

- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer
{
    if(self.zoomed==NO)
    {
        CGPoint pointInView = [recognizer locationInView:self.imageView];
        CGSize scrollViewSize = self.scrollView.bounds.size;
        CGFloat w = scrollViewSize.width / self.scrollView.maximumZoomScale;
        CGFloat h = scrollViewSize.height / self.scrollView.maximumZoomScale;
        CGFloat x = pointInView.x - (w / 2.0);
        CGFloat y = pointInView.y - (h / 2.0);

        CGRect rectToZoomTo = CGRectMake(x, y, w, h);

        [self.scrollView zoomToRect:rectToZoomTo animated:YES];
        self.zoomed = YES;
    }
    else if(self.zoomed == YES)
    {
        CGRect rectToZoomTo = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
        [self.scrollView zoomToRect:rectToZoomTo animated:YES];
        self.zoomed = NO;
    }
}

@end

It has something to do with the willAnimateToFrame method that is called when the viewController changes orientation. Any help would be greatly appreciated.


Solution

  • Got it working in case anyone is interested. I had to make some changes to my ImageZoom.m file:

    #import "ImageZoom.h"
    
    @interface ImageZoom ()
    
    @property (nonatomic, strong) UIImage *image;
    @property (nonatomic, strong) UIImageView *imageView;
    @property (nonatomic, strong) UIScrollView *scrollView;
    @property BOOL zoomed;
    
    @end
    
    @implementation ImageZoom
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self)
        {
            [self loadContentWithFrame:frame];
        }
        return self;
    }
    -(void)loadContentWithFrame:(CGRect)frame
    {
        self.scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, frame.size.width, frame.size.height)];
        self.scrollView.delegate = self;
        self.scrollView.contentSize = self.image.size;
        self.backgroundColor = [UIColor redColor];
        [self.scrollView addSubview:self.imageView];
        [self addSubview:self.scrollView];
    
        CGRect scrollViewFrame = self.scrollView.frame;
        CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
        CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
        CGFloat minScale = MIN(scaleWidth, scaleHeight);
    
        self.scrollView.minimumZoomScale = minScale;
        self.scrollView.maximumZoomScale = 1;
        self.scrollView.zoomScale = minScale;
    
        UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollViewDoubleTapped:)];
        doubleTapRecognizer.numberOfTapsRequired = 2;
        doubleTapRecognizer.numberOfTouchesRequired = 1;
        [self.scrollView addGestureRecognizer:doubleTapRecognizer];
    
        self.zoomed = NO;
    }
    
    -(void)willAnimateToFrame:(CGRect)frame
    {
        self.frame = frame;
        [self loadContentWithFrame:frame];
    }
    
    
    - (id)initWithImageView:(UIImageView *)imageView andFrame:(CGRect)frame
    {
        self.image = imageView.image;
        self.imageView = imageView;
        return [self initWithFrame:frame];
    }
    
    - (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame
    {
        self.image = image;
        self.imageView = [[UIImageView alloc] initWithImage:self.image];
        return [self initWithFrame:frame];
    }
    
    - (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return self.imageView;
    }
    
    - (void)scrollViewDidZoom:(UIScrollView *)sv
    {
        UIView* zoomView = [sv.delegate viewForZoomingInScrollView:sv];
        CGRect zoomViewFrame = zoomView.frame;
        if(zoomViewFrame.size.width < sv.bounds.size.width)
        {
            zoomViewFrame.origin.x = (sv.bounds.size.width - zoomViewFrame.size.width) / 2.0;
        }
        else
        {
            zoomViewFrame.origin.x = 0.0;
        }
        if(zoomViewFrame.size.height < sv.bounds.size.height)
        {
            zoomViewFrame.origin.y = (sv.bounds.size.height - zoomViewFrame.size.height) / 2.0;
        }
        else
        {
            zoomViewFrame.origin.y = 0.0;
        }
        zoomView.frame = zoomViewFrame;
    }
    
    - (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer
    {
        if(self.zoomed==NO)
        {
            CGPoint pointInView = [recognizer locationInView:self.imageView];
            CGSize scrollViewSize = self.scrollView.bounds.size;
            CGFloat w = scrollViewSize.width / self.scrollView.maximumZoomScale;
            CGFloat h = scrollViewSize.height / self.scrollView.maximumZoomScale;
            CGFloat x = pointInView.x - (w / 2.0);
            CGFloat y = pointInView.y - (h / 2.0);
    
            CGRect rectToZoomTo = CGRectMake(x, y, w, h);
    
            [self.scrollView zoomToRect:rectToZoomTo animated:YES];
            self.zoomed = YES;
        }
        else if(self.zoomed == YES)
        {
            CGRect rectToZoomTo = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
            [self.scrollView zoomToRect:rectToZoomTo animated:YES];
            self.zoomed = NO;
        }
    }
    
    @end