1

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

我有一个 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 的锚点视为(0.0,0.0),以考虑 CGPoint 偏移值。

所以解决办法就是将CALayer的锚点设置为(0.0, 0.0)。然后一切都按预期工作。

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

4

1 回答 1

0

您正在将平移矩阵与缩放矩阵连接起来。位移偏移的最终值将是 Offset(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);

试试这个,让我知道它是否有效。

于 2012-12-20T09:50:40.610 回答