How do I center a UIImageView within a full-screen UIScrollView?

46,408

Solution 1

This code should work on most versions of iOS (and has been tested to work on 3.1 upwards).

It's based on the Apple WWDC code for PhotoScroller.

Add the below to your subclass of UIScrollView, and replace tileContainerView with the view containing your image or tiles:

- (void)layoutSubviews {
    [super layoutSubviews];

    // center the image as it becomes smaller than the size of the screen
    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = tileContainerView.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;

    tileContainerView.frame = frameToCenter;
}

Solution 2

Have you checked out the UIViewAutoresizing options?

(from the documentation)

UIViewAutoresizing
Specifies how a view is automatically resized.

enum {
   UIViewAutoresizingNone                 = 0,
   UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
   UIViewAutoresizingFlexibleWidth        = 1 << 1,
   UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
   UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
   UIViewAutoresizingFlexibleHeight       = 1 << 4,
   UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;

Solution 3

Are you using IB to add the scroll view? Change the autosizing options of the scrollview to the attached image. alt text

Share:
46,408
Sebastian Celis
Author by

Sebastian Celis

I could list out everything programming-related that interests me... or you could look at my tags.

Updated on March 24, 2020

Comments

  • Sebastian Celis
    Sebastian Celis about 4 years

    In my application, I would like to present the user with a full-screen photo viewer much like the one used in the Photos app. This is just for a single photo and as such should be quite simple. I just want the user to be able to view this one photo with the ability to zoom and pan.

    I have most of it working. And, if I do not center my UIImageView, everything behaves perfectly. However, I really want the UIImageView to be centered on the screen when the image is sufficiently zoomed out. I do not want it stuck to the top-left corner of the scroll view.

    Once I attempt to center this view, my vertical scrollable area appears to be greater than it should be. As such, once I zoom in a little, I am able to scroll about 100 pixels past the top of the image. What am I doing wrong?

    @interface MyPhotoViewController : UIViewController <UIScrollViewDelegate>
    {
        UIImage* photo;
        UIImageView *imageView;
    }
    - (id)initWithPhoto:(UIImage *)aPhoto;
    @end
    
    @implementation MyPhotoViewController
    
    - (id)initWithPhoto:(UIImage *)aPhoto
    {
        if (self = [super init])
        {
            photo = [aPhoto retain];
    
            // Some 3.0 SDK code here to ensure this view has a full-screen
            // layout.
        }
    
        return self;
    }
    
    - (void)dealloc
    {
        [photo release];
        [imageView release];
        [super dealloc];
    }
    
    - (void)loadView
    {
        // Set the main view of this UIViewController to be a UIScrollView.
        UIScrollView *scrollView = [[UIScrollView alloc] init];
        [self setView:scrollView];
        [scrollView release];
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // Initialize the scroll view.
        CGSize photoSize = [photo size];
        UIScrollView *scrollView = (UIScrollView *)[self view];
        [scrollView setDelegate:self];
        [scrollView setBackgroundColor:[UIColor blackColor]];
    
        // Create the image view. We push the origin to (0, -44) to ensure
        // that this view displays behind the navigation bar.
        imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, -44.0,
            photoSize.width, photoSize.height)];
        [imageView setImage:photo];
        [scrollView addSubview:imageView];
    
        // Configure zooming.
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;
        CGFloat widthRatio = screenSize.width / photoSize.width;
        CGFloat heightRatio = screenSize.height / photoSize.height;
        CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
        [scrollView setMaximumZoomScale:3.0];
        [scrollView setMinimumZoomScale:initialZoom];
        [scrollView setZoomScale:initialZoom];
        [scrollView setBouncesZoom:YES];
        [scrollView setContentSize:CGSizeMake(photoSize.width * initialZoom,
            photoSize.height * initialZoom)];
    
        // Center the photo. Again we push the center point up by 44 pixels
        // to account for the translucent navigation bar.
        CGPoint scrollCenter = [scrollView center];
        [imageView setCenter:CGPointMake(scrollCenter.x,
            scrollCenter.y - 44.0)];
    }
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlackTranslucent];
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        [[[self navigationController] navigationBar] setBarStyle:UIBarStyleDefault];
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
    }
    
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return imageView;
    }
    
    @end
    
    • Andrey Tarantsov
      Andrey Tarantsov about 15 years
      What's that setZoomScale call? Are you using my ZoomScrollView?
  • Sebastian Celis
    Sebastian Celis about 15 years
    I am not using IB to add the UIScrollView. However, I think the size of the scroll view is correct. When I change the background color of my scroll view to purple, I can see that it always takes up the entire screen.
  • Sebastian Celis
    Sebastian Celis about 15 years
    Thanks, but that doesn't appear to make any difference. Calling [scrollView setBounds:[imageView bounds]]; still allows me to scroll up and down even when the image does not take up the entire vertical space of the screen.
  • JosephH
    JosephH almost 10 years
    @gyozokudor It's working for me on iOS 7; try comparing the rest of Apple's photoscroller demo code to your code and see if there's a difference? Or try putting some of your code into the photoscroller app to narrow down where the problem is.