web-dev-qa-db-ja.com

CABasicAnimation-変換スケールを中央に維持

UIViewでマスクされた楕円をアニメーション化しようとして、中央の位置にとどまったままスケール変換されます。

私は CALayer-CABasicAnimationがcenter/anchorPointを中心にスケーリングしていない を見つけ、boundsプロパティをmaskLayerCAShapeLayerに追加しましたが、これで終わりですマスクが左隅に配置され、1/4しか表示されていません。マスクを画面の中央に残したい。

@synthesize maskedView;
- (void)viewDidLoad
{
    [super viewDidLoad];
    UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"Next"];

    vc.view.frame = CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height);
vc.view.layer.bounds = self.view.layer.bounds;

    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

    CGRect maskRect = CGRectMake((self.view.frame.size.width/2)-50, (self.view.frame.size.height/2)-50, 100, 100);
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddEllipseInRect(path, nil, maskRect);
    [maskLayer setPath:path];

    CGPathRelease(path);

    vc.view.layer.mask = maskLayer;
    [self.view addSubview:vc.view];

    maskedView = vc.view;
    [self startAnimation];
}

アニメーション...

-(void)startAnimation
{
    maskedView.layer.mask.bounds = CGRectMake((self.view.frame.size.width/2)-50, (self.view.frame.size.height/2)-50, 100, 100);
    maskedView.layer.mask.anchorPoint = CGPointMake(.5,.5);
    maskedView.layer.mask.contentsGravity = @"center";

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];

    animation.duration = 1.0f;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.fromValue = [NSNumber numberWithFloat:1.0f];
    animation.toValue = [NSNumber numberWithFloat:5.0f];

    [maskedView.layer.mask addAnimation:animation forKey:@"animateMask"];
}

更新

positionキーの2番目のアニメーションでこれを修正したようです。これは正しいですか、これを行うより良い方法はありますか?

CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"position"];

animation2.duration = 1.0f;

animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

animation2.fromValue = [NSValue valueWithCGPoint:CGPointMake((self.view.frame.size.width/2), (self.view.frame.size.height/2))];
animation2.toValue = [NSValue valueWithCGPoint:CGPointMake((self.view.frame.size.width/2), (self.view.frame.size.height/2))];

[toBeMask.layer.mask addAnimation:animation2 forKey:@"animateMask2"];
20
Leon Storey

位置キーの2番目のアニメーションでこれを修正したようです。これは正しいですか、これを行うより良い方法はありますか?

CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"position"];

animation2.duration = 1.0f;

animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

animation2.fromValue = [NSValue valueWithCGPoint:CGPointMake((self.view.frame.size.width/2), (self.view.frame.size.height/2))];
animation2.toValue = [NSValue valueWithCGPoint:CGPointMake((self.view.frame.size.width/2), (self.view.frame.size.height/2))];

[toBeMask.layer.mask addAnimation:animation2 forKey:@"animateMask2"];
4
Leon Storey

次のように、(0、0)の代わりにオブジェクトの中心の周りにスケールを作成できます。

CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D tr = CATransform3DIdentity;
tr = CATransform3DTranslate(tr, self.bounds.size.width/2, self.bounds.size.height/2, 0);
tr = CATransform3DScale(tr, 3, 3, 1);
tr = CATransform3DTranslate(tr, -self.bounds.size.width/2, -self.bounds.size.height/2, 0);
scale.toValue = [NSValue valueWithCATransform3D:tr];

したがって、「アイデンティティ」変換(「変換なし」を意味する)から始めます。次に、オブジェクトの中心に移動(移動)します。次に、スケーリングします。次に、origoに戻り、開始した場所に戻ります(スケール操作にのみ影響を与えたかった)。

19
nevyn

理由はわかりませんが、CAShapeLayerは境界プロパティをレイヤーに設定しません。私の場合、それが問題でした。境界を設定してみてください。うまくいくはずです。

最初の円を作成するためにこのようなことをしました

self.circle = [CAShapeLayer layer];
CGRect roundedRect = CGRectMake(0, 0, width, width);
self.circle.bounds = roundedRect;
UIBezierPath *start = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:width/2];
[self.circle setPath:start.CGPath];
self.circle.position = CGPointMake(whatever suits you);
self.circleView.layer.mask = self.circle;
[self.circleView.layer.mask setValue: @(1) forKeyPath: @"transform.scale"];

そしてそれをスケーリングするためのこのようなもの

CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scale.fromValue = [self.circleView.layer.mask valueForKeyPath:@"transform.scale"];
scale.toValue = @(100);
scale.duration = 1.0;
scale.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.circleView.layer.mask setValue:scale.toValue forKeyPath:scale.keyPath];
[self.circleView.layer.mask addAnimation:scale forKey:scale.keyPath];

PD:AnchorPointはデフォルトで(.5、.5)Appleドキュメンテーション...

それが役に立てば幸い!!

5
facumenzella

私は多くの追加された微調整とオプションで以下の関数を書きました、他の多くの人に役立つかもしれません。

func layerScaleAnimation(layer: CALayer, duration: CFTimeInterval, fromValue: CGFloat, toValue: CGFloat) {
    let timing = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
    let scaleAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.scale")

    CATransaction.begin()
    CATransaction.setAnimationTimingFunction(timing)
    scaleAnimation.duration = duration
    scaleAnimation.fromValue = fromValue
    scaleAnimation.toValue = toValue
    layer.add(scaleAnimation, forKey: "scale")
    CATransaction.commit()
}

注: CATransactionは実際のサイズに戻るため、アニメーションの完了後にサイズを更新することを忘れないでください。

4
Aamir