【动画2】CALayer动画

一)UIView动画 

二)CoreAnimation动画


前言:上一篇已经介绍了UIKit给我们封装好的UIView动画的使用,UIKit动画是建立在CoreAnimation动画之上的,CoreAnimation是直接作用于CALayer上而非UIView。

一、CoreAnimation动画之CALayer的使用

    Layer动画和UIView动画十分相似。只需设置属性的初始值、结束值和动画执行时间,CoreAnimation会帮我们完成动画的中间过程。相对于上一篇的UIView动画,CALayer动画有着更多可设置的属性(如下列表),而且CALayer的很多子类还额外添加了更多属性(如CAShapeLayer、CAGradientLayer等),因此可实现更多的动画效果。

    1.位置和大小

    bounds

    position

    tranform:移动、缩放、旋转

    2.边框

    borderColor:边框颜色

    borderWidth:边框宽度

    cornerRadius:圆角

    3.阴影

    shadowOffset

    shadowOpacity

    shadowPath

    shadowRadius

    4.内容

    contents

    mask

    opacity


首先,我们用layer动画实现一个简单的登录页面:

    UITextField *username = [[UITextField alloc] initWithFrame:CGRectMake( -SCREENW -TEXTFIELDW , 100, TEXTFIELDW, TEXTFIELDH)];
    [username setBorderStyle:UITextBorderStyleRoundedRect];
    [username setPlaceholder:@"请输入用户名"];
    _username  = username;
    [self.view addSubview:username];
    
    UITextField *password = [[UITextField alloc] initWithFrame:CGRectMake(-SCREENW -TEXTFIELDW, 160, TEXTFIELDW, TEXTFIELDH)];
    [password setBorderStyle:UITextBorderStyleRoundedRect];
    [password setPlaceholder:@"请输入密码"];
    password.delegate = self;
    _passwork = password;
    [self.view addSubview:password];
    
    //在iOS中如果使用普通的动画则可以使用UIKit提供的动画方式来实现,如果想实现更复杂的效果,则使用Core Animation
    //Core Animation中的Animation只是普通的数据模型,只要创建模型的实例对象,直接设置对象的属性即可。
    //CABasicAnimation描述了layer动画,通过keyPath参数来指定需要改变的属性,然后设置对应属性的fromValue和toValue,最后,设置动画的持续时间。
    CABasicAnimation *flyRight = [CABasicAnimation animationWithKeyPath:@"position.x"];
    flyRight.fromValue = @(username.frame.origin.x);
    flyRight.toValue = @(SCREENW*0.5);
    flyRight.duration = 2.0;
    flyRight.fillMode = kCAFillModeBoth;
    //现在动画已经设置好了,可以将它设置给layer:
    [username.layer addAnimation:flyRight forKey:nil];
    [password.layer addAnimation:flyRight forKey:nil];



现在两个输入框确实以我们设定的动画形式出现,不过当动画结束后,输入框也随之不见了。这是为什么呢?

动画执行的时候,并非textfield本身进行移动变化,而是它的替身--呈现层(presentation layer)。既在动画开始时,textfield会隐藏,呈现层出现,在动画结束时呈现层从屏幕中移除,textfield重新变成可见,但还是在初始位置上。为了让动画停留在结束后的位置上,需要用到CABasicAnimationremovedOnCompletion属性:

flyRight.removedOnCompletion = NO;
//同时设置
flyRight.fillMode = kCAFillModeBoth;

好了,现在再看效果,动画结束后,输入框保留在最终的位置上!



不过现在有出现了一个问题,就是点击输入框,并没有弹出键盘。因为你点击的只是textfield的替身,并不能响应用户事件。为了解决这个问题,可以移除动画,并且显示真实的的textfield、更新textfield的位置属性,所以取消设置removedOnCompletion属性,改为设置textfield的位置属性:

username.layer.position = CGPointMake(SCREENW*0.5, username.layer.position.y);
password.layer.position = CGPointMake(SCREENW*0.5, password.layer.position.y);

现在运行,可以看到在动画结束之后,输入框保留在最终位置上,并且可以与用户进行交互了!

二、动画代理

有时我们希望知道动画什么时候开始或结束,可以通过动画代理实现:

fly.delegate = self;

实现动画开始和结束的方法:

- (void)animationDidStart:(CAAnimation *)anim{
    NSLog(@"start");
}


- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    NSLog(@"stop");
}

运行代码,在动画开始和结束时,会有对应的Log输出。

不过一个CABasicAnimation对象可以添加到多个CALayer对象上,要怎么确定是哪个layer动画的回调呢?CAAnimation类和其子类遵守KVC,也就是在运行时,你可以像字典一样,给它设置新的属性。

[fly setValue:@"form" forKey:@"name"];
[fly setValue:login.layer forKey:@"layer"];


上面的代码给fly设置了keyname,值为form的属性,现在可以在代理回调方法中根据name的值,从而区分不同的动画。

同时设置了keylayer,值为view.layer的属性,因此可以在回调中获取到动画对应的layer

例如,在动画结束时,加上放大动画:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    NSLog(@"stop");
    NSString *name = [anim valueForKey:@"name"];
    if([name isEqualToString:@"form"]){
        CALayer *layer = [anim valueForKey:@"layer"];
        
        CABasicAnimation *pulse = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        pulse.fromValue = @(1.25);
        pulse.toValue = @(1.0);
        pulse.duration = 0.4;
        [layer addAnimation:pulse forKey:nil];
    }
}


注意到,创建动画时,我们使用的是animationWithKeyPath:方法,在任意时刻,可以根据这里设置的key,取消动画。

[info.layer removeAnimationForKey:@"infoappear"];

三、CAAnimationGroup动画组

动画组CAAnimationGroup继承自CAAnimation,可以保存一组动画对象,将CAAnimationGroup加入CALayer之后,可以同时执行多个动画效果(也可以通过设置单个动画的beginTime来分时执行)

    CAAnimationGroup *gruopAnimation = [CAAnimationGroup animation];
    gruopAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    gruopAnimation.duration = 0.5;
    gruopAnimation.fillMode = kCAFillModeBackwards;
    
    CABasicAnimation *scaleDown =  [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleDown.fromValue = @(3.5);
    scaleDown.toValue = @(1.0);
    
    CABasicAnimation *rotate =  [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotate.fromValue = @(M_PI_4);
    rotate.toValue = @(0.0);
    
    CABasicAnimation *fade =  [CABasicAnimation animationWithKeyPath:@"transform.opacity"];
    fade.fromValue = @(0.0);
    fade.toValue = @(1.0);

    gruopAnimation.animations = @[scaleDown,rotate,fade];
    [login.layer addAnimation:gruopAnimation forKey:nil];

四、CoreAnimation实现弹簧效果

在上一篇文章介绍的UIView.animateWith。。。。方法中,我们仅仅能设置阻尼(damping)和初始速度(inital velocity)两个变量,因此有时候看起来并不十分自然。而可以通过CoreAnimation的CASpringAnimation类来实现更真实的弹簧效果,可设置的属性有:

damping - 阻尼(默认10.0)

mass- 质量(默认1.0)

stiffness-刚度(默认100.0)

inital velocity-初始速度(0.0)

因为CASpringAnimation是CABasicAnimation的子类,所以用法是一样的:


    CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"transform.scale"];
    spring.beginTime = CACurrentMediaTime()+0.8;
    spring.damping = 2.0;
    spring.fromValue = @(1.25);
    spring.toValue = @(1.0);
    spring.duration = spring.settlingDuration;
    [login.layer addAnimation:spring forKey:nil];

五、CAKeyframeAnimation

基础动画设置了fromValue和toValue,CoreAnimation根据这两个参数,在指定的一段时间内逐步改变指定的属性值。例如,当想要将layer从45°旋转到-45°时,只需要设置这两个角度值,动画过程中的值由CoreAnimation去处理。

CAKeyframeAnimation使用values属性代替了fromValue和toValue,values保存的是动画的转折点。另外还需要提供到达每个转折点的时间。

    CAKeyframeAnimation *wobble = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    wobble.duration = 0.25;
    wobble.repeatCount = 4;
    wobble.values = @[@(0.0), @(-M_PI_4/4), @(0.0), @(M_PI_4/4), @(0.0)];
    wobble.keyTimes = @[@(0.0),@(0.25),@(0.5),@(0.75),@(1.0)];
    [self.testView.layer addAnimation:wobble forKey:nil];

*如果需要改变的属性值为struct类型,例如position的类型为CGPoint,transform的类型为CATransform3D,bounds值为CGRect,均需”包装”成NSValue。


原文地址:http://blog.csdn.net/dolacmeng/article/details/52208367
demo代码:https://github.com/dolacmeng/AnimationDemo




















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值