---页首---

图层动画 一

图层内容动画 一

CoreAnimation 提供的基础结构使创建应用图层复杂动画变得很容易,并且扩展到图层支持的视图。比如改变图层结构的尺寸、位置、旋转变换、透明度; 使用CoreAnimation启动一个动画只需改变属性值一样简单,你也可创建动画且设置动画参数

动画 - 简单改变图层的属性

- 简单动画你可以隐式或显示执行,隐式动画使用默认的时间和动画属性,显示则需要自己配置动画对象的属性
- 有些基于图层的视图可以直接使用 CoreAnimation 接口,但这样做需要额外的步骤。

参考 Apple How to Animate Layer-Backed Views

// 隐式动画,直接修改属性值
theLayer.opacity = 0.0;
// 等价显示动画
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 1.0;
[theLayer addAnimation:fadeAnim forKey:@"opacity"];
// 
// 最终改变值
theLayer.opacity = 0.0;
// 显示动画最好要给 fromValue 赋值,如果不赋值则会用当前值,如果值已经更新了,则不会看到效果
- 与隐式动画不同,显示动画不会修改图层树中的数据,只生成动画,在动画结束时,动画会从图层中移除,并使用当前数据值重画该图层,如果想永久更改成显示动画的结果,  
则还必须更新图层的属性,如上面最终改变值赋值

关键帧动画 - 改变图层属性

基于属性的动画将属性从起始值改变为结束值, CAKeyframeAnimation 对象可以以线性或非线性方式对一组目标值进行动画处理;关键帧动画是由一组数据和到达该数据的时间组成。

最简单的方式让值和时间均使用一个数组,也可以使用一个路径。

// a 5-second animation of layer's positon, follow a path (CGPathRef)
// 横屏效果较明显
@interface ViewController ()
@property (nonatomic, strong) UIView *animView;
@property (nonatomic, strong) CAKeyframeAnimation *theAnimation;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.animView = [[UIView alloc] initWithFrame: CGRectMake(24, 24, 50, 50)];
    self.animView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.animView];
    CGMutablePathRef thePath = CGPathCreateMutable();
    CGPathMoveToPoint(thePath, NULL, 74, 74);
    CGPathAddCurveToPoint(thePath, NULL, 74, 500, 320, 500, 320, 74);
    CGPathAddCurveToPoint(thePath, NULL, 320, 500, 566, 500, 566, 74);
    self.theAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    self.theAnimation.path = thePath;
    self.theAnimation.duration = 5.0;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    [self.animView.layer addAnimation:self.theAnimation forKey:@"position"];
}
@end

指定 keyframe 值

- keyframe 值定义动画在执行过程中的行为,主要的方法是赋值一个对象数组,如果包含CGPoint数据(如:anchorPoint和position)的值,可以指定CGPathRef数据类型  
- 当指定数组值时,数组的数据类型取决于属性,有些对象可以直接加入数组,但有些类型在加之前要转换成 id 类型,如所有的标量或结构体,必须包装成对像,例如以下:  
- CGRect --> NSValue
- CATransform3D --> NSValue
- borderColor 属性类型 CGColorRef --> id
- CGFloat --> NSNumber
- 图层的 contents 属性 --> CGImageRef  

指定 keyframe 动画时间

关键帧动画的时间和步调比基础动画更复杂,可以通过几个属性去控制。  
`calculationMode` 属性定义用于计算动画时间的算法,且影响其它时间相关属性使用  
	- 线性或立体动画是当 `calculationMode` 属性值为 `kCAAnimationLinear` 或 `kCAAnimationCubic`,可以最大程度控制动画的时间
	- 步调动画是当 `calculationMode` 属性值为 `kCAAnimationPaced` 或 `kCAAnimationCubicPaced`, 将不依赖于 `keyTimes` 或 `timingFunction` 提供的时间,  
	而是隐式的计算时间,让动画具有恒定的速度
	- 离散或不连续动画是当 `calculationMode` 属性值为 `kCAAnimationDiscrete`,不需要插值就可以从关键帧值跳到下一个,此种模式使用 `keyTimes` 属性的值而忽略 `timingFunctions` 属性的值
`keyTimes` 属性指定应用每个关键帧的时间标记,只有计算模式为 `kCAAnimationDiscrete` 、 `kCAAnimationLinear` 或 `kCAAnimationCubic`可使用,不用于步调动画  
`timingFunctions` 属性指定应用每个关键帧的时间曲线(此属性替换了继承的TimingFunction属性)  

如果要自己处理动画时间,请使用 kCAAnimationLinearkCAAnimationCubic 模式以及 keyTimestimingFunction 属性。keyTimes定义了应用每个关键帧值的时间点,所有中间值的时序均由时间函数功能控制,允许为每个阶段应用曲线的缓入或缓出,如果未指定,则是线性的

停止正在执行的显示动画

动画通常运行直到结束,但在下列几种情况之一可以轻松停止动画:
- 调用 `removeAnimationForKey: ` 从图层中移除单一动画对象,此处 key 是你调用 `addAnimation:forKey:` 时使用的,且不能为 `nil`.
- 调用 `removeAllAnimations ` 移除图层所有动画,立即移除所有正在执行的动画,用图层当前信息重绘图层

隐式动画不可直接移除
当从图层中移除动画时, CoreAnimation 会使用当前值来重绘图层做出响应,因为当前值通常是结束值,所以会产生突然的跳动一下,如果想外观保持在动画结束时的样子,可以从表现树中获取最终值,赋值给图层树中的对象。

多改变同时动画

如果同时对图层进行多个动画,可以使用 CAAnimationGroup ,使用动画组对管理多动画对象更简单,时间和持续时间动画组同样会遵循。

 // Animation 1
CAKeyframeAnimation * widthAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderWidth"];
NSArray *widthValues = [NSArray arrayWithObjects:@1.0, @5.0, @30.0, @0.5, @2.0, @50.0, @0.0, nil];
widthAnim.values = widthValues;
widthAnim.calculationMode = kCAAnimationPaced;
// Animation 2
CAKeyframeAnimation *colorAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderColor"];
NSArray *colorValues = [NSArray arrayWithObjects:(id)[UIColor greenColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil];
colorAnim.values = colorValues;
colorAnim.calculationMode = kCAAnimationPaced;
// Animation Group
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil];
group.duration = 5.0;
[self.animView.layer addAnimation:group forKey:@"BorderChanges"];

更高级的动画组使用事务对象处理,可参考 Explicit Transactions Let You Change Animation Parameters

检测动画结束

- 有两种方法可以检查动画的状态
	+ 添加一个完成的 block,使用 `setCompletionBlock:` 方法,当事务中所有的动画结束,会执行这个block
	+ 给 CAAnimation 对象设置代理并实现 `animationDidStart:` 和 `animationDidStop: finished:` 方法

如果你想在一个动画结束时去开始另一个动画,不要使用上面的动画通知方法,请使用 beginTime 属性,将第二个动画的开始时间设置为第一个动画的结束时间。

参考 Custom the Timing of an Animation

如何实现基于图层视图动画(iOS)

- 推荐使用 UIKit 中自带的动画接口,如果要使用 Core Animation 类初始化动画,需要将所有的 Core Animation 的调用都要放在视图动画块中,任何在动画块外的改变都 不会生效
[UIView animateWithDuration:1.0 animations:^{
   // Change the opacity implicitly.
   myView.layer.opacity = 0.0;
   // Change the position explicitly.
   CABasicAnimation* theAnim = [CABasicAnimation animationWithKeyPath:@"position"];
   theAnim.fromValue = [NSValue valueWithCGPoint:myView.layer.position];
   theAnim.toValue = [NSValue valueWithCGPoint:myNewPosition];
   theAnim.duration = 3.0;
   [myView.layer addAnimation:theAnim forKey:@"AnimateFrame"];
}];
- 如果是基于约束实现视图,那在动画时可以先将约束删除、改变、然后添加需要的约束。
posted @ 2020-02-10 14:50  20190311  阅读(255)  评论(0编辑  收藏  举报
---页脚---