25

Right now I have a view that is outside of the UIScrollView. For many reasons, it cannot be simply inside the scrollview. So right now what i'm doing is, as the UIScrollView is scaled/panned, I update my other auxiliary view. The only issue i'm coming into is, the zoomScale value is not adjusted for while the view is bouncing back to either the minimum or maximum scale. Any suggestions on how to obtain this value while it animates back?

Sample code:

self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, appSize.width, appSize.height)];
self.scrollView.contentSize = CGSizeMake(appSize.width * 2, appSize.height * 2);

self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.scrollView.delegate = self;
self.scrollView.bounces = YES;
self.scrollView.bouncesZoom = YES;
self.scrollView.alwaysBounceHorizontal = YES;
self.scrollView.alwaysBounceVertical = YES;
self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;

self.scrollViewZoomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,
                                                                   appSize.width * 2,
                                                                   appSize.height * 2)];
[[self scrollView] addSubview:self.scrollViewZoomView];

float minZoomScale = 2.0f;

self.scrollView.minimumZoomScale = minZoomScale;
self.scrollView.maximumZoomScale = 1.0f;
self.scrollView.zoomScale = self.scrollView.minimumZoomScale;

and then on self

-(void) scrollViewDidZoom:(UIScrollView *)scrollView {
    float scale = [scrollView zoomScale];
    [self updateAuxViewScale:scale];
}
Steve Kanter
  • 305
  • 3
  • 8
  • Can't you just animate the auxiliary view to its min/max scale when `scrollViewDidEndZooming:withView:atScale:` is called? I think the "bounce back" animation has a fixed duration. – omz Apr 03 '13 at 13:24

5 Answers5

7

The bouncing back of the zoom is an animation, so the property zoomScale is immediately the target value of the animation, even if the animation is still running. If you would like to apply the same zoom scale that the scroll view has to another view, here is a way to retrieve it:

  1. In -scrollViewDidScroll: check whether the content view has animations.
  2. If there are no animations, only set the new zoom scale.
  3. If there are animations, get the duration of one of them (the durations should all be equal), and animate your view with that duration to the new zoom scale.

That approach is not elegant, but it works. Here is some code to get you started:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat zoomScale = _scrollView.zoomScale;

    CALayer *layer = _contentView.layer;
    NSArray *animationKeys = [layer animationKeys];

    if (animationKeys.count == 0) {
        // set zoomScale on target view
    } else {
        CFTimeInterval duration = 0.0;
        for (NSString *animationKey in animationKeys) {
            CAAnimation *animation = [layer animationForKey:animationKey];
            duration = animation.duration;
            break;
        }
        // easeInEaseOut is the default animation when the zoom bounces
        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            // set zoomScale on target view
        } completion:nil];
    }
}
Tammo Freese
  • 10,514
  • 2
  • 35
  • 44
  • This looks like a promising approach. Can you explain why you store _previousZoomScale I don't see it being used anywhere. – combinatorial Apr 03 '13 at 15:54
  • Good point, in my test project I stored both the old and the new value, but if you set the zoom on another object anyway, you only need the new value. I'll adapt may answer accordingly. – Tammo Freese Apr 03 '13 at 16:44
5

Thanks to this answer it becomes clear that one can use the presentationLayer to get the correct values. I created a UIScrollView category to add special getters for zoomScale, contentOffset and contentSize which return the correct values even if the UIScrollView is animating.

You can find the repo here: https://github.com/bddckr/BDDRScrollViewExtensions

Community
  • 1
  • 1
bddckr
  • 1,393
  • 13
  • 11
  • I'm using this approach but I'm finding that frequently, the final values of the presentation layer do not match to what they should. It's as if it stops short. – Benjohn Aug 11 '15 at 15:17
2

You should use a different UIScrollViewDelegate method.

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
    // Your code here
    float scale = [scrollView zoomScale];
    [self updateAuxViewScale:scale];
}

According to the docs: https://developer.apple.com/library/ios/#documentation/uikit/reference/uiscrollviewdelegate_protocol/Reference/UIScrollViewDelegate.html

"The scroll view also calls this method after any “bounce” animations."

David Braun
  • 782
  • 1
  • 9
  • 18
  • 5
    I totally forgot about this post until now. I've been dealing with it as is, but wish to fix it before launch. The problem is, I can determine the scale when the user is actively zooming, as well as when the "bounce" animations are finished, but it's the actual animation that I wish to forward on. During the zoom-bounce animation, I wish to know what the CURRENT zoom is - that is, the zoom level at a particular interval in the animation. – Steve Kanter Apr 03 '12 at 21:07
  • 1
    I really want to solve this too. I am now looking into KVO to watch the presentationLayer of the view but I dont get any callback on that either. Would love to solve this. – bobmoff Oct 11 '12 at 20:40
1

Okay, I think I may have found something that will help you. In this related thread In iOS 4.0, why does UIScrollView zoomToRect:animated: not trigger the scrollViewDidScroll or scrollViewDidZoom delegates while animating?, there are two answers that may be of use to you.

  1. https://stackoverflow.com/a/15512253/1011213
  2. https://stackoverflow.com/a/7553969/1011213

Personally, I think I would give the first solution a shot. Hope I understand the question and this is helpful. If not.. apologies and most blissful coding!

Community
  • 1
  • 1
codeqi
  • 753
  • 1
  • 6
  • 14
-2

As per my knowledge, if you want to know current zoom level, you should use following delegate method for UIScrollView

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{

       NSLog(@"Zoomscale %f",scale);

}

Hope this will be useful to you.

Enjoy Programming!!

Niru Mukund Shah
  • 4,637
  • 2
  • 20
  • 34
  • This solution does not actually solve my issue. My problem is, I want to know what the current zoom scale is during the bounce-zoom portion of the animation. I've attempted every single delegate method, as well as KVO to no avail. – Steve Kanter Apr 02 '13 at 13:35
  • ohh.. Why so. I did the same in my app using this delegate method only.. !! – Niru Mukund Shah Apr 02 '13 at 13:37
  • 1
    Because my view is behind an invisible UIScrollView. I'm using the UIScrollView for its physics - so i'm passing the scale factor from the UIScrollView through to an auxiliary view. That's why I need to know what the zoom scale is, even while it's bouncing back from an animation. – Steve Kanter Apr 02 '13 at 13:46