我已经为此工作了一段时间,并彻底搜索了一个解决方案,但无济于事。这是我想要做的。
我有一个 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];
}
当上面的图层动画时,内容被正确缩放,但位置不正确。内容似乎比我预期的要多x
,y
因此不能完全追溯用户在 UIScrollView 上所做的缩放/平移。
有什么想法我可能做错了吗?
回答
好的,我知道我做错了什么。它与 CALayer 的锚点有关。CALayers 上的变换总是应用于锚点。对于 CALayers,锚点默认为 (0.5, 0.5)。所以缩放和平移是沿着中心点进行的。另一方面,UIScrollViews 从视图的左上角给出偏移量。基本上,您可以将 UIScrollView 的锚点视为(0.0,0.0),以考虑 CGPoint 偏移值。
所以解决办法就是将CALayer的锚点设置为(0.0, 0.0)。然后一切都按预期工作。
还有其他资源以更好的方式呈现此信息。请参阅 Stackoverflow 上类似的另一个问题。另请参阅Apple 文档中的这篇文章,其中详细讨论了几何中的位置、锚点和一般层。