ios CABasicAnimation - 变换比例保持在中心

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16447236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:31:03  来源:igfitidea点击:

CABasicAnimation - transform scale keep in center

ioscore-animationcore-graphicsmaskcatransform3d

提问by Leon Storey

Trying to animatie an ellipse masked on a UIView to be scale transformed remaining in the center position.

试图在 UIView 上对蒙版的椭圆进行动画处理,以保留在中心位置进行缩放。

I have found CALayer - CABasicAnimation not scaling around center/anchorPoint, and followed by adding a boundsproperty to the maskLayerCAShapeLayerhowever, this ends with the mask being positioned in the left corner with only 1/4 of it showing. I would like the mask to remain within the center of the screen.

我发现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];
}

Animation...

动画片...

-(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"];
}


Update

更新

I seem to have fixed this with a second animation on the positionkey. Is this correct or is there a better way of doing this?

我似乎已经用position键上的第二个动画修复了这个问题。这是正确的还是有更好的方法来做到这一点?

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"];

采纳答案by Leon Storey

I seem to have fixed this with a second animation on the position key. Is this correct or is there a better way of doing this?

我似乎已经用位置键上的第二个动画修复了这个问题。这是正确的还是有更好的方法来做到这一点?

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"];

回答by nevyn

You can create a scale around the center of the object instead of (0, 0) like this:

您可以创建围绕对象中心而不是 (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];

So we start out with the "identity" transform (which means 'no transform'). Then we translate (move) to the center of the object. Then we scale. Then we move back to origo so we're back where we started (we only wanted to affect the scale operation).

所以我们从“身份”变换开始(这意味着“无变换”)。然后我们平移(移动)到对象的中心。然后我们进行缩放。然后我们回到原点,回到我们开始的地方(我们只想影响缩放操作)。

回答by facumenzella

I am not sure why, but CAShapeLayer does not set the bounds property to the layer. In my case, that's was the problem. Try setting the bounds. That should work.

我不知道为什么,但 CAShapeLayer 没有为图层设置 bounds 属性。就我而言,这就是问题所在。尝试设置界限。那应该工作。

I did something like this for building the initial circle

我做了这样的事情来建立初始圈

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"];

And something like this for scaling it

像这样的东西来缩放它

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 is by default (.5,.5) according to apple documentations...but we all know that does not mean anything right?

PD:根据苹果文档,AnchorPoint 默认为 (.5,.5) ......但我们都知道这并不意味着什么,对吗?

Hope it helps!!

希望能帮助到你!!

回答by Aamir

I have written following function with many added tweaks and options, could be useful for many others.

我编写了以下功能,并添加了许多调整和选项,可能对其他人有用。

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()
}

Note:Don't forget to update size after animation completion, because CATransaction reverts back to actual size.

注意:不要忘记在动画完成后更新大小,因为 CATransaction 会恢复到实际大小。