您的位置:首页 > 移动开发 > IOS开发

ios SDK开发之关于CoreAnimation的一些注意点总结

2016-10-15 23:05 676 查看
关于UIView animation,很多读者相信非常喜欢用animation block的动画API,如下:

[html] view
plain copy

Animating Views with Blocks

+ animateWithDuration:delay:options:animations:completion:

+ animateWithDuration:animations:completion:

+ animateWithDuration:animations:

+ transitionWithView:duration:options:animations:completion:

+ transitionFromView:toView:duration:options:completion:

当然笔者也一样,但是关于block还是有一些需要注意的地方的,比如:关于动画的意外停止,在动画的时候,突然按Home键退出应用。笔者前几日碰到一个关于类似的UIViewAnimation方面的bug,在这里记录一下。请看如下的代码:

[html] view
plain copy

- (void)animationMoveViewRightOut:(UIView *)view completion:(void (^)(BOOL finished))completion {

[UIView animateWithDuration:1.0f animations:^{

CGRect bounds = [UIScreen mainScreen].bounds;

view.center = CGPointMake( bounds.size.width + view.frame.size.width/2, view.center.y);

}completion:^(BOOL finished ) {

if (completion) {

completion(finished);

}

}];

}

- (void)animationMoveViewToCenter:(UIView *)view {

[UIView animateWithDuration:1.0f delay:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{

CGRect bounds = [UIScreen mainScreen].bounds;

view.center = CGPointMake(bounds.size.width / 2, bounds.size.height / 2 );

}completion:^ (BOOL finished){

if (finished) {

[self animationMoveViewRightOut:view completion:^(BOOL finished) {

if (finished) {

NSLog(@"animationMoveViewRightOut!!!");

}

}];

}

}];

}

这段动画代码就是先将某个view动画移动到屏幕中央,移动到中央的动画结束的时候接着将该视图移动出右边的屏幕之外。你能看出这段动画有啥问题么?这段代码平时运行的挺好的,完全没啥问题,但是当执行移动视图到屏幕中间期间,按下Home键,应用进入后台,再进入前台的时候,你可能会发现,视图没有移动出屏幕之外,动画被冻结了。为什么呢?笔者发现,当屏幕进入后台的时候,UIview的block动画会瞬间完成,并执行completion块动画,这时传递过去的finished的bool值是false,completion里关于移动视图到屏幕外边的动画就不会执行了。

发现这个问题之后,笔者将所有动画结束的 if(finished)判断语句去掉。这时在移动视图到屏幕中央期间再按下Home键,让应用进入后台,再进入前台,这时视图已经看不见了,从打印的信息能看到 “animationMoveViewRightOut!!!”的语句,这表明视图移动到右边屏幕外的动画已经瞬间执行了。好,关于UIViewblock动画注意点总结:1动画期间,当按下Home键时,动画将会瞬间完成;2.动画虽然是瞬间完成了,但是completion的返回的finishedbool值是false

为解决这个问题,如果你不需要在从后台进入前台继续执行动画,你可以将所有的finish判断语句去掉,这个让动画瞬间完成,防止导致一些意外情况;另外你也可以在进入后台的时候用[aView.layerremoveAllAnimations];语句来将该视图的所有动画remove掉,动画也会瞬间完成。在此多解释几句:[aView.layer removeAllAnimations];仅可以removeCABasicAnimationCoreAnimation动画,也可以remove掉所有的UIView
animation
就是类似文章开头的API动画以及UIImageViewanimationImagesstartAnimating的序列帧动画,由此可见,UIImageView的序列帧动画以及UIView
animation
的插值动画的底层实现都是用CoreAnimation实现的。见如下代码实例:

[html] view
plain copy

aView = [[UIImageView alloc] initWithFrame:CGRectMake(0, viewController.view.frame.size.height /2 - 50, 100, 100)];

aView.backgroundColor = [UIColor redColor];

aView.animationDuration = 10;

aView.animationImages = [NSArray arrayWithObjects: [UIImage imageNamed: @"CloseNormal.png"],[UIImage imageNamed: @"Icon.png"],[UIImage imageNamed: @"CloseSelected.png"],[UIImage imageNamed:@"Icon-Small-50.png" ], nil];

[aView startAnimating];

[viewController.view addSubview:aView];

[aView release];

[self animationMoveViewToCenter:aView];

[self performSelector:@selector(removeAnimation:) withObject:nil afterDelay:2];

- (void)removeAnimation:(id)sender {

// [aView stopAnimating];

[aView.layer removeAllAnimations];

}

所以,如果你想要能控制更多的动画内容,比如你想能够在进入后台的时候让动画停止,进入前台的时候又让动画恢复运行,你可以尝试用CoreAnimation来实现动画。代码实例如下:

[html] view
plain copy

- (void)rotationAnimation:(UIView *)view {

CABasicAnimation *rotation;

rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];

rotation.toValue = [NSNumber numberWithFloat: M_PI * 2];

rotation.duration = 5;

rotation.cumulative = YES;

rotation.repeatCount = 4;

rotation.removedOnCompletion = NO;

rotation.fillMode = kCAFillModeForwards;

rotation.delegate = self;

[view.layer addAnimation:rotation forKey:@"rotationAnimation"];

}

- (void)animationDidStart:(CAAnimation *)theAnimation {

NSLog(@"animationDidStar");

}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {

NSLog(@"animationDidStop finished %d",flag);

}

[self rotationAnimation:aView];[self performSelector:@selector(removeAnimation:) withObject:nil afterDelay:2];

//注意,第一次pauseLayer的时候,就会触发 - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 函数,以后将不会再次触发,或者[aView.layer removeAllAnimations];也能触发;总之,- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag只会被触发一次,触发一次之后,再次发生能触发该函数的情况将不再调用该函数。

-(void)pauseLayer:(CALayer*)layer //暂停动画

{

CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];

layer.speed = 0.0;

layer.timeOffset = pausedTime;

}

-(void)resumeLayer:(CALayer*)layer //恢复动画

{

CFTimeInterval pausedTime = [layer timeOffset];

layer.speed = 1.0;

layer.timeOffset = 0.0;

layer.beginTime = 0.0;

CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;

layer.beginTime = timeSincePause;

}

- (void)applicationDidBecomeActive:(UIApplication *)application {

/*

Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

*/

[self resumeLayer:aView.layer];

}

- (void)applicationDidEnterBackground:(UIApplication *)application {

/*

Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.

If your application supports background execution, called instead of applicationWillTerminate: when the user quits.

*/

[self pauseLayer:aView.layer];

}

好了,再次总结一下,调用以上-(void)pauseLayer:(CALayer*)layer函数,可以暂停一个layer tree的所有animation;而调用上面提供的-(void)resumeLayer:(CALayer*)layer函数可以恢复一个layer
tree的所有animation。本篇到此结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: