master_gracey
master_gracey

Reputation: 354

Changing centering of content within UIScrollView

I have a UIScrollView with an UIImageView as the content. It displays fine, and scrolls fine. No problems there. The image is considerably wider than the screen, so I want to be able to "auto center" a specific portion (coordinates) of the image within the scrollview.

Here is where I'm stuck, though. The desired centering location will dynamically change based on the use of the application, so I need to be able to configure it so that a desired coordinate of the image view (x,y) is centered automatically within the scrollview when loaded. It doesn't have to autoscroll/animate, it just needs to be there.

I've seen similar questions/answers for centering content when gestures/zooming are being used, but neither are employed here. Just scrolling. I just need to be able to have a set portion of the image be centered within the scrollview when it first loads.

I hope I've made sense. Thanks for your time.

Upvotes: 3

Views: 8629

Answers (4)

Matt Connolly
Matt Connolly

Reputation: 9847

Simply setting its position in the scrollview works. For example:

- (void)centreImageView
{
    CGRect bounds = self.bounds;
    CGSize contentSize = self.contentSize;
    CGFloat offsetX = MAX(0, (bounds.size.width - contentSize.width) * 0.5f);
    CGFloat offsetY = MAX(0, (bounds.size.height - contentSize.height) * 0.5f);

    _myContentView.center = CGPointMake(contentSize.width * 0.5 + offsetX, contentSize.height * 0.5 + offsetY);
}

And call that in your initialisation and also from - (void)scrollViewDidZoom:(UIScrollView *)scrollView if you are zooming.

Upvotes: 1

CodaFi
CodaFi

Reputation: 43330

I'm on an iPhone right now, so excuse me if this code is a little funky, as I can't remember exactly if the center property is available without calling size.center first...

CGPoint centerOffset = CGPointMake(0, [scrollView contentSize].(size).center);
[scrollView setContentOffset: centerOffset animated: YES]; // (or No, depends on you)

Upvotes: 5

Yariv Nissim
Yariv Nissim

Reputation: 13343

After a few days of researching this issue I came up with a simple solution using the ScrollView property - contentInset. This will always center the image, even while zooming (if you follow all instructions).

- (void)centerImage
{
    if (!self.image) return;

    CGFloat imageScaleWidth = self.image.size.width * self.scrollView.zoomScale;
    CGFloat imageScaleHeight = self.image.size.height * self.scrollView.zoomScale;

    CGFloat hOffset = (self.frame.size.width - imageScaleWidth) * 0.5f;
    CGFloat vOffset = (self.frame.size.height - imageScaleHeight) * 0.5f;

    if (hOffset < 0) hOffset = 0;
    if (vOffset < 0) vOffset = 0;

    self.scrollView.contentInset = UIEdgeInsetsMake(vOffset, hOffset, 0, 0);
}

Call this method in the ScrollView delegate:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    [self centerImage];
}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
    [self centerImage];
}

AND when you layout your SubViews:

- (void)layoutScrollView
{
    if (!self.image) return;

    CGFloat heightScale = self.frame.size.height / self.image.size.height;
    CGFloat widthScale = self.frame.size.width / self.image.size.width;
    CGFloat scale = MIN(widthScale, heightScale);

    self.scrollView.minimumZoomScale = scale;
    self.scrollView.maximumZoomScale = MAX(1.0f ,scale * 2.0f);
    [self.scrollView setZoomScale:self.scrollView.minimumZoomScale animated:NO];

    [self centerImage];
}

Upvotes: 2

Josh Sherick
Josh Sherick

Reputation: 2161

Not sure if this is what you are looking for but I just thought I would put it out there, does this method help?

- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {

    CGRect zoomRect;

    // the zoom rect is in the content view's coordinates. 
    //    At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
    //    As the zoom scale decreases, so more content is visible, the size of the rect grows.
    zoomRect.size.height = [scroller frame].size.height / scale;
    zoomRect.size.width  = [scroller frame].size.width  / scale;

    // choose an origin so as to get the right center.
    zoomRect.origin.x    = center.x - (zoomRect.size.width  / 2.0);
    zoomRect.origin.y    = center.y - (zoomRect.size.height / 2.0);

    return zoomRect;
}

Or this one?

- (CGRect)zoomRectForScale:(float)scale withOrigin:(CGPoint)origin {

    CGRect zoomRect;

    // the zoom rect is in the content view's coordinates. 
    //    At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
    //    As the zoom scale decreases, so more content is visible, the size of the rect grows.
    zoomRect.size.height = [scroller frame].size.height / scale;
    zoomRect.size.width  = [scroller frame].size.width  / scale;

    // choose an origin so as to get the right center.
    zoomRect.origin.x    = origin.x;
    zoomRect.origin.y    = origin.y;

    return zoomRect;
}

Note: I didn't write these, they are from sample code provided by Apple but I use them occasionally and I thought of them when I saw your question.

Upvotes: 0

Related Questions