【动画2】CALayer动画

    xiaoxiao2025-07-11  4

    一)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

    转载请注明原文地址: https://ju.6miu.com/read-1300600.html
    最新回复(0)