CALayer上的转换属性的CAKeyFrameAnimation未按预期工作

时间:2012-12-19 05:57:06

标签: ios uiscrollview calayer cakeyframeanimation translate-animation

我已经在这方面工作了一段时间并彻底搜索了一个解决方案,但无济于事。这是我想要做的。

我有一个UIScrollView,用户可以在其上放大和平移5秒钟。我有一个单独的CALayer,它没有分层在UIScrollView之上。我想缩放和翻译此CALayer的内容,以反映UIScrollView上发生的缩放和平移。我想通过关键帧动画CAKeyFrameAnimation来实现这一点。当我将其放入代码中时,缩放按预期发生,但内容的位置偏移不正确。

以下是我在代码中的操作方法。假设UIScrollView委托将缩放比例和内容偏移量传递给以下方法:

// Remember all zoom params for late recreation via a CAKeyFrameAnimation
- (void) didZoomOrScroll:(float)zoomScale
           contentOffset:(CGPoint)scrollViewContentOffset {

    CATransform3D scale = CATransform3DMakeScale(zoomScale, zoomScale, 1);
    CATransform3D translate = CATransform3DMakeTranslation(-scrollViewContentOffset.x, 
                                                           -scrollViewContentOffset.y, 0);
    CATransform3D concat = CATransform3DConcat(scale, translate);

    // _zoomScrollTransforms and _zoomScrollTimes below are of type NSMutableArray
    [_zoomScrollTransforms addObject:[NSValue valueWithCATransform3D:concat]];

    // secondsElapsed below keeps track of time
    [_zoomScrollTimes addObject:[NSNumber numberWithFloat:secondsElapsed]];
}

// Construct layer animation
- (void) constructLayerWithAnimation:(CALayer *)layer {

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    animation.duration = 5.0;
    animation.values = _zoomScrollTransforms;

    // Adjust key frame times to contain fractional durations
    NSMutableArray *keyTimes = [[NSMutableArray alloc] init];
    for( int i = 0; i < [_zoomScrollTimes count]; i++ ) {
          NSNumber *number = (NSNumber *)[_zoomScrollTimes objectAtIndex:i];
          NSNumber *fractionalDuration = [NSNumber numberWithFloat:[number          floatValue]/animation.duration];
         [keyTimes addObject:fractionalDuration];
    }
    animation.keyTimes = keyTimes;

    animation.removedOnCompletion = YES;
    animation.beginTime = 0;
    animation.calculationMode = kCAAnimationDiscrete;
    animation.fillMode = kCAFillModeForwards;
    [layer addAnimation:animation forKey:nil];
}

对上面的图层进行动画处理时,内容会正确缩放,但定位不正确。内容似乎是xy移动的次数超出了我的预期,因此无法完全回溯用户在UIScrollView上完成的缩放/平移。

任何想法我可能做错了什么?

答案

好的,我弄清楚我做错了什么。它与CALayer的锚点有关。 CALayers上的变换始终应用于锚点。对于CALayers,默认情况下锚点为(0.5,0.5)。因此,沿着中心点进行缩放和翻译。另一方面,UIScrollViews从视图的左上角提供偏移量。基本上,您可以将UIScrollView的锚点视为考虑CGPoint偏移值,为(0.0,0.0)。

因此解决方案是将CALayer的锚点设置为(0.0,0.0)。然后一切都按预期工作。

还有其他资源以更好的方式呈现此信息。请参阅Stackoverflow上的另一个问题similar。另请参阅Apple文档中的this article,其中详细讨论了几何中的位置,锚点和一般图层。

1 个答案:

答案 0 :(得分:0)

您将翻译矩阵与缩放矩阵连接起来。位移偏移的最终值将为偏移(X,Y)=(scaleX * Tx,scaleY * Ty)。

如果你想用(Tx,Ty)偏移移动UIView,而不是连接翻译和缩放矩阵,如下所示:

CATransform3D scale = CATransform3DMakeScale(zoomScale, zoomScale, 1);
CATransform3D translate = CATransform3DMakeTranslation(-scrollViewContentOffset.x, 
                                                       -scrollViewContentOffset.y, 0);
CATransform3D concat = CATransform3DConcat(translate, scale);

试试这个并告诉我它是否有效。