I have a view in UIScrollView in which the user can zoom into.
The view has the same size as the UIScrollView frame. However, the subviews of that view are bigger and ce
The behavior can be changed to zooming around the center, but the technique is tricky.
Suppose you have a scroll view of size (300,300) with a single zoomable subview, self.imageView
, located initially at (0,0,300,300). Now you want to zoom out. What is happening is that the contentOffset
always remains (0,0) as you zoom out. This leads to the appearance that you are zooming with the anchor point at top-left corner.
However, changing the anchor point on any views will not help here; this is because the zooming behavior of the scroll view is not just a zoom transformation applied to some subview. The appearance of content in scroll view is controlled by contentInset
and contentOffset
, which are separate variables maintained by the scroll view. You need to modify the behavior of the content offset and the content inset during zoom.
One solution is to adjust the contentInset
dynamically as the scrollview scrolls. The purpose is to keep the image always centered in the visible area of the scroll view.
When initializing the scroll view, prepare its frame like this:
- (void) viewDidLoad {
//// .......
self.scrollView.zoomScale = 1;
self.scrollView.minimumZoomScale = fminf(1, fminf(self.scrollView.frame.size.width/(self.imageView.image.size.width+1), self.scrollView.frame.size.height/(self.imageView.image.size.height+1)));
CGFloat leftMargin = (self.scrollView.frame.size.width - self.imageView.image.size.width)*0.5;
CGFloat topMargin = (self.scrollView.frame.size.height - self.imageView.image.size.height)*0.5;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
[self assignInsetsOnScroller]; // this has to be done before settings contentOffset!
self.scrollView.contentOffset = CGPointMake(fmaxf(0,-leftMargin), fmaxf(0,-topMargin));
self.scrollView.contentSize = CGSizeMake(fmaxf(self.imageView.image.size.width, self.scrollView.frame.size.width+1), fmaxf(self.imageView.image.size.height, self.scrollView.frame.size.height+1));
}
Set up a delegate for the scroll view, override scrollViewDidScroll:
, and do something like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self assignInsetsOnScroller];
}
- (void) assignInsetsOnScroller {
CGFloat leftMargin = (scrollView.frame.size.width - self.imageView.frame.size.width)*0.5;
CGFloat topMargin = (scrollView.frame.size.height - self.imageView.frame.size.height)*0.5;
scrollView.contentInset = UIEdgeInsetsMake(fmaxf(0, topMargin), fmaxf(0, leftMargin), 0, 0);
}
Each pinch gesture will give rise to a scrolling action. The result is that the insets are adjusted dynamically, so that the imageView
always appears to be in the center of the scroll view.