开机动画开门效果实现中遇到的隐式动画问题

来源:互联网 发布:微课制作软件免费 编辑:程序博客网 时间:2024/04/27 01:57
毫无疑问,要用layer来做,定义两个layer,一个是leftLayer, 一个是rightLayer,内容分别是开机图片的左半边和右半边,然后设置其围绕y轴旋转的transform了,再然后就是设置动画时间,代码如下所示

    CATransform3D transform = CATransform3DIdentity;
    transform.
m34 = 1.0/2500.0;
    
    [
UIView animateWithDuration:3.0 animations:^{
        
leftLayer.transform = CATransform3DRotate(transform, -M_PI/2010);
        
rightLayer.transform = CATransform3DRotate(transform, M_PI/2010);
    }];

本人一直比较习惯用UIView自带的动画,但是这样设置后发现,无论动画时间设置多少,运行起来都是固定的,很快。经过网上搜索资料才发现,原来CALayer有些隐藏动画,比如,位置,透明度和颜色改变的时候,它都有自己的隐式动画,所以自己设置的动画就和隐式动画冲突,看到这,一般的思路就是把隐式动画这个属性设置为NO,我也是这么想,在CALayer里面找了半天,试了很多都不是,最后在网上看到关闭隐式动画的语句,如下:
    [CATransaction setDisableActions:YES];

在上面的UIView动画前面加上这句话就可以把隐式动画给取消掉。但是问题又来了,无论怎么设置时间,都没有动画了,都是瞬间完成,我了个去。又经过大量查证和实践,解决方法代码如下:
    CATransform3D transform = CATransform3DIdentity;
    transform.
m34 = 1.0/2500.0;
    
    [
leftLayer removeAllAnimations];
    [
rightLayer removeAllAnimations];
    
    [
CATransaction begin];
    [
CATransaction setAnimationDuration:5.0];
    
    
leftLayer.transform = CATransform3DRotate(transform, -M_PI/2010);
    
rightLayer.transform = CATransform3DRotate(transform, M_PI/2010);
    
    [CATransaction commit];

其中,[leftLayer removeAllAnimations];[rightLayer removeAllAnimations];两句话要不要都是可以的。

可能是因为隐式动画的类型就是CATransaction类型的吧,所以你自己设计的动画也要用CATansaction,具体还有没有其他的实现方法,我还真不知道,谁发现了,希望通知我一下。

不要以为这样就完了,正当我以为这样就把所有问题解决了的时候,又遇到一个比较蛋疼的问题,是关于线程的。如下,在实现开机动画的开门效果的时候,我最主要写了两个方法,如下:
- (void)prepareStartAnimation
{
    
UIImage *image = [imageView imageOfView];
    
    
leftLayer = [CALayer layer];
    
leftLayer.anchorPoint = CGPointMake(00.5);
    
leftLayer.frame = CGRectMake(00512748);
    
leftLayer.contentsGravity = kCAGravityLeft;
    
leftLayer.masksToBounds = YES;
    
leftLayer.contents = (id)[image CGImage];
    [
self.layer addSublayer:leftLayer];
    
    
rightLayer = [CALayer layer];
    
rightLayer.anchorPoint = CGPointMake(1.00.5);
    
rightLayer.frame = CGRectMake(5120512748);
    
rightLayer.contentsGravity = kCAGravityRight;
    
rightLayer.masksToBounds = YES;
    
rightLayer.contents = (id)[image CGImage];
    [
self.layer addSublayer:rightLayer];
    
    [
imageView removeFromSuperview];
}

- (
void)startAnimation
{
    
CATransform3D transform = CATransform3DIdentity;
    transform.
m34 = 1.0/2500.0;
    
    [
leftLayer removeAllAnimations];
    [
rightLayer removeAllAnimations];
    
    [
CATransaction begin];
    [
CATransaction setAnimationDuration:5.0];
    
    
leftLayer.transform = CATransform3DRotate(transform, -M_PI/2010);
    
rightLayer.transform = CATransform3DRotate(transform, M_PI/2010);
    
    [
CATransaction commit];
}

第一个方法是准备工作,将imageView保存成图片,然后分别填充到左右两个layer中,第二个方法就是动画开始的方法了,调用的时候先调用第一个方法,然后再调用第一个方法,这时候问题出现了,如果两个方法连着调用,如下:
        [animationView prepareStartAnimation];
        [animationView startAnimation];
动画效果就没有了,但是如果调用第一个方法后延迟一下,即使延迟一点点时间,运行都是正常的,代码如下:
    [animationView prepareStartAnimation];
    
 double delayInSeconds = 0;
    
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [animationView 
startAnimation];
    });

如上所示,延迟时间设置为0都可以,但是将两个方法连着调用就是不行。如果有大神知道为什么欢迎一起讨论。下面将此效果实现代码奉上:
AnimationView.h
#import <UIKit/UIKit.h>
#import 
<QuartzCore/QuartzCore.h>

@interface AnimationView : UIView

- (
void)prepareStartAnimation;

- (
void)startAnimation;

@end

AnimationView.m
#import "AnimationView.h"

@interface UIView (extented)

- (
UIImage *)imageOfView;

@end

@implementation UIView (extented)

- (
UIImage *)imageOfView
{
    
UIGraphicsBeginImageContext(self.bounds.size);
    [
self.layer renderInContext:UIGraphicsGetCurrentContext()];
    
    
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
UIGraphicsEndImageContext();
    
    
return image;
}

@end

@interface AnimationView ()
{
    
__weak IBOutlet UIImageView *imageView;
    
    
CALayer *leftLayer;
    
CALayer *rightLayer;
}
@end

@implementation AnimationView

- (
id)initWithFrame:(CGRect)frame
{
    
self = [super initWithFrame:frame];
    
if (self) {
        
// Initialization code
    }
    
return self;
}

- (
void)prepareStartAnimation
{
    
UIImage *image = [imageView imageOfView];
    
    
leftLayer = [CALayer layer];
    
leftLayer.anchorPoint = CGPointMake(00.5);
    
leftLayer.frame = CGRectMake(00512748);
    
leftLayer.contentsGravity = kCAGravityLeft;
    
leftLayer.masksToBounds = YES;
    
leftLayer.contents = (id)[image CGImage];
    [
self.layer addSublayer:leftLayer];
    
    
rightLayer = [CALayer layer];
    
rightLayer.anchorPoint = CGPointMake(1.00.5);
    
rightLayer.frame = CGRectMake(5120512748);
    
rightLayer.contentsGravity = kCAGravityRight;
    
rightLayer.masksToBounds = YES;
    
rightLayer.contents = (id)[image CGImage];
    [
self.layer addSublayer:rightLayer];
    
    [
imageView removeFromSuperview];
}

- (
void)startAnimation
{
    
CATransform3D transform = CATransform3DIdentity;
    transform.
m34 = 1.0/2500.0;
    
    [
leftLayer removeAllAnimations];
    [
rightLayer removeAllAnimations];
    
    [
CATransaction begin];
    [
CATransaction setAnimationDuration:5.0];
    
    
leftLayer.transform = CATransform3DRotate(transform, -M_PI/2010);
    
rightLayer.transform = CATransform3DRotate(transform, M_PI/2010);
    
    [
CATransaction commit];
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/


@end
该类的xib文件中就一个imageView。以下是调用的代码:
MainViewController.m
- (void)viewDidLoad
{
    [
super viewDidLoad];
// Do any additional setup after loading the view.
    
    
AnimationView *animationView = [[[NSBundle mainBundleloadNibNamed:@"AnimationView" owner:self           options:nillastObject];
    
    [
self.view addSubview:animationView];
    
    [animationView 
prepareStartAnimation];
    
double delayInSeconds = 0;
    
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        
        [animationView 
startAnimation];
    });
    
    
double delayInSeconds1 = 6.5;
    
dispatch_time_t popTime1 = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds1 * NSEC_PER_SEC));
    
dispatch_after(popTime1, dispatch_get_main_queue(), ^(void){
        [animationView 
removeFromSuperview];
    });
}