在iOS 4.0中,为什么UIScrollView zoomToRect:animated:在animation时不触发scrollViewDidScroll或scrollViewDidZoom委托?

我需要密切关注滚动视图的大小,以便根据滚动视图的animation缩放更新内容视图的元素(pipe理多个CALayer的子视图)。

在iOS 3.1上,一切正常,我使用zoomToRect:animated:animation发生时UIScrollViewDelegatescrollViewDidScroll:消息被重复调用 ,让我根据实际的缩放更新子视图元素。

iOS 4.0上的相同代码并不performance出相同的行为。 当我调用zoomToRect:animated:,委托( scrollViewDidScroll:scrollViewDidZoom )只被调用一次 ,这使得我的子元素不同步,直到animation完成。 事实上,子元素会立即跳转,然后被缩放animation捕捉,直到所有的东西都在正确的位置。 就好像animation没有在子视图CALayers上进行修改。

我曾尝试用animation块手动animation,但情况是相同的,没有渐进式callback调用。 我也尝试过KVO,但是我不清楚如何使用UIScrollViewpipe理的animation。

在iOS 4中是否有一种解决方法,当UIScrollView缩放比例是dynamic的时候,我可以将缩放值推送到子视图中?

残酷但工作。

定义一些属性:

@property (nonatomic, strong) UIView *zoomedView; @property (nonatomic, strong) CADisplayLink *displayLink; @property (nonatomic) CGFloat currentScale; 

通知UIScrollView UIView将被放大:

 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.zoomedView; } 

注册一个CADisplayLink 。 它也运行核心animation,所以它将以相同的时间间隔被踢:

 self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick)]; [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

查看zoomedView的presentationLayer获取当前值。

 - (void)displayLinkTick { CALayer *zoomedLayer = self.zoomedView.layer.presentationLayer; CGFloat scale = zoomedLayer.transform.m11; if (scale != self.currentScale) { self.currentScale = scale; // update property // the scale has changed! } } 

在IOS 4.0中,animation是由操作系统完成的 – 我假定尽可能使用基于GPU的硬件加速。 作为一个缺点,使从另一个(animation)值导出的值变得更难。 在你的情况下,取决于UIScrollView的缩放级别的子视图的位置。 为了做到这一点,你应该设置子视图的animation与放大的animation并行。 尝试像这样:

 [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{ theScrollView.zoomScale = zoomScale; // layout the subviews here } completion:^(BOOL finished) {}]; 

这应该在相同的animation上下文中设置子视图的框架属性,因此,它们应该由OS一起animation。

另请参阅此问题的答案: 如何使UIScrollView在animation过程中发送scrollViewDidScroll消息

更新animation块(或开始/提交animation)内的所有子视图是否可行? 就像是:

 [self zoomToRect:zoomRect animated:YES]; [UIView animateWithDuration:1.0 animations:^ { // change your subviews } ]; 

调用zoomToRect:animated:之后,注册UIScrollViewzoomScale属性的KVO zoomToRect:animated:

 [scrollView addObserver:self forKeyPath:@"zoomScale" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; 

然后,执行这个方法:

 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"zoomScale"]) { // use the new zoomScale value stored // in the NSKeyValueChangeNewKey change // dictionary key to resize your subviews } // be sure to call the super implementation // if the superclass implements it [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } 

查看KVO 文档 。