CABasicAnimation - масштаб преобразования в центре
Попытка анимации эллипса, замаскированного на UIView, масштабироваться, оставаясь в центральном положении.
Я нашел CALayer - CABasicAnimation не масштабируется вокруг 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];
}
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"];
}
Обновление
Кажется, я исправил это со второй анимацией на клавише 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"];
Ответы
Ответ 1
Кажется, я исправил это со второй анимацией в ключе позиции. Это правильно или есть лучший способ сделать это?
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"];
Ответ 2
Вы можете создать масштаб вокруг центра объекта вместо (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];
Итак, мы начинаем с преобразования "идентичности" (что означает "нет преобразования" ). Затем мы переводим (перемещаемся) в центр объекта. Затем мы масштабируем. Затем мы возвращаемся к ориу, чтобы вернуться туда, где мы начали (мы хотели только повлиять на масштабную операцию).
Ответ 3
Я не уверен, почему, но 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 по умолчанию (.5,.5) по документам Apple... но все мы знаем, что это ничего не значит?
Надеюсь, что это поможет!
Ответ 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 возвращается к фактическому размеру.