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

        关于UIView animation,很多读者相信非常喜欢用animation block的动画API,如下:

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,在这里记录一下。请看如下的代码:

- (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键,应用进入后台,再进入前台的时候,你可能会发现,视图没有移动出屏幕之外,动画被冻结了。为什么呢?笔者发现,当屏幕进入后台的时候,UIviewblock动画会瞬间完成,并执行completion块动画,这时传递过去的finishedbool值是falsecompletion里关于移动视图到屏幕外边的动画就不会执行了。

       发现这个问题之后,笔者将所有动画结束的 iffinished)判断语句去掉。这时在移动视图到屏幕中央期间再按下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实现的。见如下代码实例:

    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实现动画。代码实例如下:

- (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。本篇到此结束。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值