29

我需要密切监视滚动视图的比例,以便我可以根据滚动视图的动画缩放更新内容视图的元素(管理多个CALayers的子视图)。

在 iOS 3.1 上,一切都按预期工作,我使用zoomToRect:animated:并且UIScrollViewDelegate的scrollViewDidScroll:消息在动画发生时被重复调用,让我根据实际缩放更新子视图元素。

iOS 4.0 上的相同代码不会表现出相同的行为。当我调用zoomToRect:animated:时,代表(scrollViewDidScroll:scrollViewDidZoom)只被调用一次,这使得我的子元素去同步直到动画完成。实际上,子元素会立即跳跃,然后被缩放动画赶上,直到一切都在正确的位置。就好像动画没有拾取子视图CALayers上的修改。

我曾尝试使用动画块手动制作动画,但情况相同,没有渐进式回调调用。我也尝试过 KVO,但我不清楚如何利用 UIScrollView 管理的动画。

在 iOS 4 上是否有一种解决方法可以让我在UIScrollView缩放动画时将缩放值推送到我的子视图?

4

4 回答 4

10

残酷但有效。

定义一些属性:

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

通知UIScrollViewUIView要缩放的内容:

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

注册一个CADisplayLink滴答声。它也运行核心动画,所以它会以相同的间隔被踢:

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!
    }
}
于 2013-03-19T23:08:59.930 回答
1

在 IOS 4.0 中,动画由操作系统完成——我假设尽可能使用基于 GPU 的硬件加速。这样做的一个缺点是,对从另一个(动画)值派生的值进行动画处理变得更加困难。与您的情况一样,子视图的位置取决于 UIScrollView 的缩放级别。为了实现这一点,您应该将子视图的动画设置为与缩放动画平行。尝试类似:

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

这应该在相同的动画上下文中设置子视图的帧属性,因此,它们应该由操作系统一起设置动画。

另请参阅此问题的答案:How to make UIScrollView send scrollViewDidScroll messages during animations

于 2011-09-26T10:50:59.903 回答
-1

在您调用后注册该zoomScale属性的KVO 。UIScrollViewzoomToRect: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文档

于 2010-11-15T20:15:29.447 回答
-1

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

[self zoomToRect:zoomRect animated:YES];
[UIView animateWithDuration:1.0
    animations:^ {
        // change your subviews
    }
];
于 2010-11-12T15:06:58.820 回答