Last active
June 9, 2024 14:12
-
-
Save TimOliver/71be0a8048af4bd86ede to your computer and use it in GitHub Desktop.
Zooming to a specific CGPoint inside a UIScrollView (2015 Edition)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@implementation UIScrollView (ZoomToPoint) | |
/** | |
Zooms into the specified point of the scroll view's zoomable content view at the supplied scaled. | |
(The zoomable content view is the view that is returned in `viewForZoomingInScrollView:` | |
@param zoomPoint - In terms of the scroll view's co-ordinate space, the point to zoom to | |
@param scale - A value between minimumZoomScale and maximumZoomScale in which to zoom to. | |
@param animated - Whether the transition is animated, or instant | |
*/ | |
- (void)zoomToPoint:(CGPoint)zoomPoint withScale:(CGFloat)scale animated:(BOOL)animated | |
{ | |
//Ensure scale is clamped to the scroll view's allowed zooming range | |
scale = MIN(scale, self.maximumZoomScale); | |
scale = MAX(scale, self.minimumZoomScale); | |
//`zoomToRect` works on the assumption that the input frame is in relation | |
//to the content view when zoomScale is 1.0 | |
//Work out in the current zoomScale, where on the contentView we are zooming | |
CGPoint translatedZoomPoint = CGPointZero; | |
translatedZoomPoint.x = zoomPoint.x + self.contentOffset.x; | |
translatedZoomPoint.y = zoomPoint.y + self.contentOffset.y; | |
//Figure out what zoom scale we need to get back to default 1.0f | |
CGFloat zoomFactor = 1.0f / self.zoomScale; | |
//By multiplying by the zoom factor, we get where we're zooming to, at scale 1.0f; | |
translatedZoomPoint.x *= zoomFactor; | |
translatedZoomPoint.y *= zoomFactor; | |
//work out the size of the rect to zoom to, and place it with the zoom point in the middle | |
CGRect destinationRect = CGRectZero; | |
destinationRect.size.width = CGRectGetWidth(self.frame) / scale; | |
destinationRect.size.height = CGRectGetHeight(self.frame) / scale; | |
destinationRect.origin.x = translatedZoomPoint.x - (CGRectGetWidth(destinationRect) * 0.5f); | |
destinationRect.origin.y = translatedZoomPoint.y - (CGRectGetHeight(destinationRect) * 0.5f); | |
if (animated) { | |
[UIView animateWithDuration:0.55f delay:0.0f usingSpringWithDamping:1.0f initialSpringVelocity:0.6f options:UIViewAnimationOptionAllowUserInteraction animations:^{ | |
[self zoomToRect:destinationRect animated:NO]; | |
} completion:^(BOOL completed) { | |
if ([self.delegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) { | |
[self.delegate scrollViewDidEndZooming:self withView:[self.delegate viewForZoomingInScrollView:self] atScale:scale]; | |
} | |
}]; | |
} | |
else { | |
[self zoomToRect:destinationRect animated:NO]; | |
} | |
} | |
@end |
@kmaschke85
Thanks, but it isn't animating. Happen to know why? Thanks in advance!
@kmaschke85 Thanks for posting that, but it isn't animating for some reason. Happen to know how to solve that?
Thanks in advance for explaining!
Sorry @01GOD can't tell. It's animating fine for me. Can you provide an example where it's not working for you?
@kmaschke85 Seems there is an issue with the UIView animation system in that app not animating. I built a custom animator for that today.
Thanks works really great!!! Here a swift version of your code:
extension UIScrollView { func zoom(toPoint zoomPoint : CGPoint, scale : CGFloat, animated : Bool) { var scale = CGFloat.minimum(scale, maximumZoomScale) scale = CGFloat.maximum(scale, self.minimumZoomScale) var translatedZoomPoint : CGPoint = .zero translatedZoomPoint.x = zoomPoint.x + contentOffset.x translatedZoomPoint.y = zoomPoint.y + contentOffset.y let zoomFactor = 1.0 / zoomScale translatedZoomPoint.x *= zoomFactor translatedZoomPoint.y *= zoomFactor var destinationRect : CGRect = .zero destinationRect.size.width = frame.width / scale destinationRect.size.height = frame.height / scale destinationRect.origin.x = translatedZoomPoint.x - destinationRect.width * 0.5 destinationRect.origin.y = translatedZoomPoint.y - destinationRect.height * 0.5 if animated { UIView.animate(withDuration: 0.55, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.6, options: [.allowUserInteraction], animations: { self.zoom(to: destinationRect, animated: false) }, completion: { completed in if let delegate = self.delegate, delegate.responds(to: #selector(UIScrollViewDelegate.scrollViewDidEndZooming(_:with:atScale:))), let view = delegate.viewForZooming?(in: self) { delegate.scrollViewDidEndZooming!(self, with: view, atScale: scale) } }) } else { zoom(to: destinationRect, animated: false) } } }
👍🏼
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@kmaschke85 Thanks works great!