1

私はしばらくこれに取り組んでおり、解決策を徹底的に検索しましたが、役に立ちませんでした。これが私がやろうとしていることです。

ユーザーが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 でユーザーが行ったズーム/パンを正確にたどることができませんxy

私が間違っているかもしれないアイデアはありますか?

答え

わかりました、私は自分が間違っていたことを理解しました。これは、CALayer のアンカー ポイントに関係していました。CALayer の変換は、常にアンカー ポイントに適用されます。CALayers の場合、アンカー ポイントはデフォルトで (0.5, 0.5) です。そのため、中心点に沿ってスケーリングと変換が行われていました。一方、UIScrollViews は、ビューの左上隅からのオフセットを提供します。基本的に、CGPoint オフセット値を (0.0, 0.0) として考える目的で、UIScrollView のアンカー ポイントを考えることができます。

したがって、解決策は、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 に答える