Reputation: 1481
Can anyone precisely describe the behavior of -[UIScrollView zoomToRect:animated:]
? This method really seems to do some complicated stuff, but Apple's documentation of it is very sparse.
I am getting unpredictable behavior of this method when the content size is smaller than the size of the scroll view in width and/or height. In some cases, this method causes the scroll view to have a negative content offset when it should be 0. Passing slightly different rects, it leaves the content offset at 0 like I would expect.
To demonstrate this weird behavior, I set up an example project with a scroll view of size (200, 200) containing a content view of size (100, 100). I would expect that zooming to rect ((0, 0), (200, 200)) of the content view should leave the content in the top left (i.e. nothing should happen). However, it actually causes the content to scroll to the bottom right of the scroll view's bounds (content offset (-100, -100)). Why does this happen?
Here is the code in my example project:
@implementation RootViewController
- (void)loadView {
self.view = [[UIView alloc] init];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
self.scrollView.delegate = self;
self.scrollView.backgroundColor = [UIColor whiteColor];
self.scrollView.minimumZoomScale = .5;
self.scrollView.maximumZoomScale = 4;
self.contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.contentView.backgroundColor = [UIColor redColor];
[self.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]];
[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.frame.size;
[self.view addSubview:self.scrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.contentView;
}
- (void)handleTap {
[self.scrollView zoomToRect:CGRectMake(0, 0, 200, 200) animated:YES]; // Try changing to 199, 199 to get completely different behavior
}
@end
Thanks for any insights! Right now I am guessing UIScrollView
just isn't designed to display content smaller than its own size. My use case is that I may have a content view that is wider than the scroll view but shorter in height, and I need to be able to scroll to either the right or left end of this content view programmatically.
Upvotes: 4
Views: 940
Reputation: 1481
If anyone is wondering, this is what I may do in this case. I'm going to see if it plays well with the unit tests for the scroll view subclass I'm implementing in my real life project. However, this doesn't answer the original question of "Can anyone precisely describe the behavior of -[UIScrollView zoomToRect:animated:]
?" so I'm still hoping for more answers.
Well, here goes (I hate hackery like this):
@implementation TBScrollView // Subclass of UIScrollView
- (void)setContentOffset:(CGPoint)contentOffset {
contentOffset.x = MAX(contentOffset.x, 0);
contentOffset.y = MAX(contentOffset.y, 0);
[super setContentOffset:contentOffset];
}
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
contentOffset.x = MAX(contentOffset.x, 0);
contentOffset.y = MAX(contentOffset.y, 0);
[super setContentOffset:contentOffset animated:animated];
}
@end
EDIT: Unfortunately this has the unfortunate side effect that you can no longer bounce scrolling on the left side for larger images where that should be allowed (requires negative content offset). I'm going to look for another solution to my use case.
EDIT 2: I got around the above-mentioned side effect by only disabling negative content offsets while a -zoomToRect:animated:
animation is taking place. I declared a BOOL
property, set it to YES
before calling -zoomToRect:animated:
, and set it back to NO
afterwards if animated
was NO
. Otherwise, I set the property to NO
during -scrollViewDidEndScrollingAnimation:
(called if -zoomToRect:animated:
didn't cause any change in scale) and -scrollViewDidEndZooming:withView:atScale:
(called if -zoomToRect:animated:
did cause a change in scale). This is kind of a hacky solution and I worry that it may break with a future iOS release, but at least I have it all supported by unit tests :)
Upvotes: 2
Reputation: 1481
Unless someone has a better answer, I'm going to conclude that calling -zoomToRect:animated:
has undefined results when the resulting contentSize
is smaller than the bounds
size in either dimension. In other words, the content should be larger than the scroll view if you want to be safe.
Upvotes: 3