2013-05-08 1 views
14

Попытка анимации эллипса, замаскированного в UIView, масштабироваться, оставаясь в центральном положении.CABasicAnimation - преобразование масштаба в центре

Я нашел CALayer - CABasicAnimation not scaling around 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

Я, кажется, исправил со второй анимации на ключе 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"]; 

ответ

6

Я, кажется, исправил это с помощью второй анимации на клавише позиции. Это правильно или есть лучший способ сделать это?

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

Вы можете создать шкалу вокруг центра объекта, а (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]; 

Итак, мы начинаем с «идентичность» преобразованием (что означает «нет преобразование '). Затем мы переводим (перемещаемся) в центр объекта. Затем мы масштабируем. Затем мы возвращаемся к ориу, поэтому мы вернулись туда, где мы начали (мы только хотели повлиять на масштабную операцию).

+0

Не влияет ли масштабирование на перевод, сделанный после него? Я тестирую это (а также с нормальным аффинным преобразованием), и вид всегда заканчивается сверху слева от его первоначальной позиции. – Ixx

+0

Этот был сработал в моем случае 'CABasicAnimation * scale = [CABasicAnimation animationWithKeyPath: @" transform "]; CATransform3D tr = CATransform3DIdentity; tr = CATransform3DScale (tr, 3, 3, 1); шкала.toValue = [NSValue valueWithCATransform3D: tr]; ' –

4

Я не уверен, почему, но CAShapeLayer не устанавливает свойство bounds в этот слой. В моем случае это была проблема. Попробуйте установить границы. Это должно сработать.

я сделал что-то подобное для создания первоначального круга

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 по умолчанию (0,5 ,. 5) в соответствии с документацией на яблоко ... но мы все знаем, что это ничего не значит?

Надеюсь, это поможет!

3

Я написал следующую функцию со многими добавленными настройками и настройками, может быть полезен для многих других.

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 возвращается к фактическому размеру.

+0

скруббер? ,.,./,. –

+0

Предполагается, что скруббер будет слоем? anywas. помогли мне очень хорошо. спасибо>) –

+1

@DavidSeek да его слой не скруббер, я обновил свой ответ спасибо. – Aamir