CABasicAnimation - 变换比例保持在中心

时间:2013-05-08 17:59:05

标签: ios core-animation core-graphics mask catransform3d

尝试在UIView上屏蔽椭圆,以进行比例变换,保留在中心位置。

我找到了CALayer - CABasicAnimation not scaling around center/anchorPoint,然后向bounds maskLayer添加了CAShapeLayer属性,但是,结果是掩码只位于左角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键上的第二个动画修复了这个问题。这是正确的还是更好的方法呢?

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 个答案:

答案 0 :(得分:18)

您可以围绕对象的中心创建缩放而不是(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,所以我们回到了我们开始的地方(我们只想影响规模操作)。

答案 1 :(得分:5)

我不确定原因,但CAShapeLayer没有为图层设置bounds属性。就我而言,那就是问题所在。 尝试设置边界。这应该有用。

我做了类似的事情来构建初始圈

html, body {
     height: 100%;
     padding: 0;
     margin: 0;
}

.container {
     height: 100%;
     background: url(link/to/image) center center;
     background-size: cover; 
     // Use prefixes
}

.inner-container {
    background-color: rgba(255, 255, 255, 0.6);
    color: #000;
    width: 500px;
    margin: 60px auto;
}

以及缩放它的类似内容

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

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

希望它有所帮助!!

答案 2 :(得分:4)

我好像用位置键上的第二个动画修复了这个问题。这是正确的还是更好的方法呢?

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

答案 3 :(得分:4)

我已经编写了以下函数,其中包含许多附加的调整和选项,对许多其他人都有用。

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会恢复到实际尺寸。