UIScrollView with centered UIImageView, like Photos app

Martin Ludvik picture Martin Ludvik · Mar 12, 2009 · Viewed 39k times · Source

I would like to have scroll view with an image content view. The image is actually map which is much bigger than the screen. The map should be initially in the center of the scroll view, like photos in Photos app when you turn iPhone to landscape orientation.

alt text

I did not manage to have the map in the center with correct zooming and scrolling at the same time. Provided that the map image starts from the top of the screen (in portrait orientation), the code looks something like:

- (void)loadView {
    mapView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"map.jpg"]];
    CGFloat mapHeight = MAP_HEIGHT * SCREEN_WIDTH / MAP_WIDTH;
    mapView.frame = CGRectMake(0, 0, SCREEN_WIDTH, mapHeight);
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    scrollView.delegate = self;
    scrollView.contentSize = mapView.frame.size;
    scrollView.maximumZoomScale = MAP_WIDTH / SCREEN_WIDTH;
    scrollView.minimumZoomScale = 1;
    [scrollView addSubview:mapView];
    self.view = scrollView;
}

When I move the image frame to the center, the image grows only from the top of its frame down. I tried to play around with mapView transform, with dynamically changing frame of the imageView. Nothing works for me so far.

Answer

JosephH picture JosephH · Aug 13, 2010

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 mentioned in Jonah's answer.

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