После нескольких попыток у меня наконец-то заработали анимации.Есть несколько вещей, за которыми нужно следить.
Если вы хотите, чтобы преобразование было закреплено в центре, то вам следует позвонить anchorPoint
на CALayer:
перед добавлением вид на его суперпредставление!В противном случае подпредставление будет обрезано, начиная с местоположения anchorPoint
.
CALayer *layer = _completionIndicator.layer;
layer.anchorPoint = CGPointMake(.5, .5);
Обернуть вызовы анимации в блоке runAnimationGroup
(_completionIndicator
- это свойство, определенное какNSView
и centerInSuperview
определены ниже):
[self.contentView addSubview:_completionIndicator];
[_completionIndicator centerInSuperview];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
CGFloat duration = <#duration#>;
CALayer *layer = _completionIndicator.layer;
CABasicAnimation *animation;
//Transform
animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(<#scale#>, <#scale#>, 1.0)];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
[animation setDuration:duration];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[layer addAnimation:animation forKey:@"zoomIn"];
//Fade
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = [NSNumber numberWithFloat:0.0];
animation.toValue = [NSNumber numberWithFloat:1.0];
[animation setDuration:duration];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[layer addAnimation:animation forKey:@"fadeIn"];
} completionHandler:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[NSThread sleepForTimeInterval:<#seconds#>];
dispatch_sync(dispatch_get_main_queue(), ^{
[self hideCompletionIndicator];
});
});
}];
Установка fillMode
была необходима для плавной анимации.По умолчанию kCAFillModeRemoved
, что вызывает скачки при запуске анимации после первого запуска.
В OSX 10.11 установка wantsLayer
в NSView
не требуется.Я не знаю о предыдущих версиях.
Чтобы скрыть вид, просто сделайте обратное и удалите вид в блоке завершения:
- (void) hideCompletionIndicator
{
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
CGFloat duration = <#duration#>;
CALayer *layer = _completionIndicator.layer;
CABasicAnimation *animation;
//Transform
animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(<#scale#>, <#scale#>, 1.0)];
[animation setDuration:duration];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[layer addAnimation:animation forKey:@"zoomOut"];
//Fade
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = [NSNumber numberWithFloat:1.0];
animation.toValue = [NSNumber numberWithFloat:0.0];
[animation setDuration:duration];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[layer addAnimation:animation forKey:@"fadeOut"];
} completionHandler:^{
[_completionIndicator removeFromSuperview];
}];
}
Реализация категории NSView
@implementation NSView (Additions)
- (void) centerInSuperview
{
[self centerInView:[self superview]];
}
- (void) centerInView:(NSView *)otherView
{
int w = self.frame.size.width;
int h = self.frame.size.height;
int x = (otherView.frame.size.width - w)/2;
int y = (otherView.frame.size.height - h)/2;
self.frame = NSMakeRect(x, y, w, h);
}
@end
Интерфейс категории NSView
@interface NSView (Additions)
- (void) centerInSuperview;
- (void) centerInView:(NSView *)otherView;
@end