私はしばらくこれに取り組んでおり、解決策を徹底的に検索しましたが、役に立ちませんでした。これが私がやろうとしていることです。
ユーザーが5秒間ズームおよびパンできるUIScrollViewがあります。UIScrollView の上にレイヤー化されていない別の CALayer があります。UIScrollView で発生するズームとパンを反映するために、この CALayer のコンテンツをスケーリングおよび変換したいと考えています。キー フレーム アニメーションでこれを実現したいと考えています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];
}
上のレイヤーをアニメーション化すると、コンテンツは適切にズームされますが、位置が正しくありません。コンテンツが予想以上にずれているように見え、その結果、UIScrollView でユーザーが行ったズーム/パンを正確にたどることができませんx
。y
私が間違っているかもしれないアイデアはありますか?
答え
わかりました、私は自分が間違っていたことを理解しました。これは、CALayer のアンカー ポイントに関係していました。CALayer の変換は、常にアンカー ポイントに適用されます。CALayers の場合、アンカー ポイントはデフォルトで (0.5, 0.5) です。そのため、中心点に沿ってスケーリングと変換が行われていました。一方、UIScrollViews は、ビューの左上隅からのオフセットを提供します。基本的に、CGPoint オフセット値を (0.0, 0.0) として考える目的で、UIScrollView のアンカー ポイントを考えることができます。
したがって、解決策は、CALayer のアンカー ポイントを (0.0, 0.0) に設定することです。そして、すべてが期待どおりに機能します。
この情報をより適切な方法で提示する他のリソースがあります。同様の Stackoverflow に関するこの他の質問を参照してください。ジオメトリの位置、アンカーポイント、および一般的なレイヤーについて詳しく説明している Apple のドキュメントのこの記事も参照してください。