iOS 动画专题(UIView二维形变动画与CAAnimation核心动画)

文章目录

  1. iOS动画

  2. UIView动画
    2.1 设置UIView动画的两种语法形式
    2.2 设置属性形变动画的两种类型
    2.3 与动画相关的属性
    2.3.1 UIView与动画相关的属性--与CGAffineTransform对应
    2.4 管理二维形变和三维形变的封装类:CGAffineTransform与CATransform3D
    2.4.1 CGAffineTransform操作API
    CGAffineTransform操作API
    2.4.2 CATransform3D操作API
    2.4.3 CATransform3D与CGAffineTransform相互转换API
    2.5 “组合动画” 与 CGAffineTransformConcat
    2.5.1 连接设置多个属性组合成一个动画
    2.5.2 利用CGAffineTransformConcat设置组合动画
    2.6 动画后将属性还原
    2.7 注意点: transform对frame的影响

  3. CAAnimation核心动画
    3.1 设置动画的一种语法形式
    3.2 CAAnimation继承结构
    3.3 CAAnimation类的属性
    3.4 几个重要属性值
    removedOnCompletion属性值
    fillMode属性值
    timingFunction属性值

  4. CABasicAnimation
    4.1 特别属性说明:
    4.2 keyPath可以是哪些值
    4.3 举例

  5. CAKeyframeAnimation关键帧动画
    5.1 参数数组形式
    5.2 path形式

  6. 组动画
    6.1 组动画
    6.2 示例

  7. 贝塞尔曲线
    7.1 CGMutablePathRef
    7.2 UIBezierPath

  8. iOS动画
    总的来说,从涉及类的形式来看,iOS动画有:基于UIView的仿射形变动画,基于CAAnimation及其子类的动画,基于CG的动画。这篇文章着重总结前两种动画。

  9. UIView动画
    设置UIView形变动画有两种常见用到的属性,.frame,.transform,所以有的人也可以分别称之为:

① frame动画
② transform动画

这两种动画只需要在动画语法中适当的位置,基于UIView和CALayer的属性设置变化值即可。这种动画,不需要 调用核心动画CAAnimation里面的专用类和API。

其中,frame动画设置方式有限,必须确切地制定形变前后的frame,平移还好,特别是 旋转 的时候,只能通过数学知识计算出新的frame。这就得不偿失了。所以,更多的时候,当涉及一些frame,bounds,center的改变或是形变的时候可以用transform来取代frame。

2.1 设置UIView动画的两种语法形式
begin — commit

//偏移动画
[UIView beginAnimations:@"move" context:nil];
[UIView setAnimationDuration:2];
[UIView setAnimationDelegate:self];
imageContainView.frame = CGRectMake(80, 80, 200, 200);
[label1 setBackgroundColor:[UIColor yellowColor]];
[label1 setTextColor:[UIColor redColor]];
[UIView commitAnimations];
1
2
3
4
5
6
7
8
animations block

//缩放动画
view.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:1.0f animations:^{
view.transform = CGAffineTransformMakeScale(2.0f, 2.0f);
}];
1
2
3
4
5
2.2 设置属性形变动画的两种类型
UIView的 CGAffineTransform 类型属性:animatedView.transform
一般是View的旋转,拉伸移动等属性,是二维的,通常使用都是前缀CGAffineTransform的类。

CGAffineTransform transform = CGAffineTransformScale(imageContainView.transform, 1.2, 1.2);
[UIView beginAnimations: @"scale"context: nil];
[UIView setAnimationDuration: 2];
[UIView setAnimationDelegate: self];
[imageView setTransform: transform];
[UIView commitAnimations];
1
2
3
4
5
6
CALayer的CATransform3D 类型属性:animaView.layer.transform
通过 .layer.transform 可以在3D模式下面的变化,通常使用的都是前缀为CATransform3D的类。

imageView.layer.transform = CATransform3DIdentity;
[UIView animateWithDuration:1.0f animations:^{
imageView.layer.transform = CATransform3DMakeScale(2.0, 2.0, 1.0);
}];
1
2
3
4
2.3 与动画相关的属性
2.3.1 UIView与动画相关的属性–与CGAffineTransform对应
下面是UIView的一些属性介绍

@property(nonatomic) CGRect frame;
@property(nonatomic) CGRect bounds; // default bounds is zero origin, frame size. animatable
@property(nonatomic) CGPoint center; // center is center of frame. animatable
@property(nonatomic) CGAffineTransform transform; // default is CGAffineTransformIdentity. animatable
@property(nonatomic) CGFloat contentScaleFactor NS_AVAILABLE_IOS(4_0);

@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled __TVOS_PROHIBITED; // default is NO
@property(nonatomic,getter=isExclusiveTouch) BOOL exclusiveTouch __TVOS_PROHIBITED; // default is NO
1
2
3
4
5
6
7
8
在实际开发中,使用场景:

(1) 当涉及一些frame, bounds, center的改变或是形变的时候可以用 transform 来取代 frame。
(2) 一般在实际开发中都是平移,旋转,缩放组合使用。

2.3.2 CALayer与动画相关的属性–与CATransform3D对应

下面是CALayer的一些属性介绍

//宽度和高度
@property CGRect bounds;

//位置(默认指中点,具体由anchorPoint决定)
@property CGPoint position;

//锚点(x,y的范围都是0-1),决定了position的含义
@property CGPoint anchorPoint;

//背景颜色(CGColorRef类型)
@property CGColorRef backgroundColor;

//形变属性
@property CATransform3D transform;

//边框颜色(CGColorRef类型)
@property CGColorRef borderColor;

//边框宽度
@property CGFloat borderWidth;

//圆角半径
@property CGFloat cornerRadius;

//内容(比如设置为图片CGImageRef)
@property(retain) id contents;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2.4 管理二维形变和三维形变的封装类:CGAffineTransform与CATransform3D
2.4.1 CGAffineTransform操作API
CGAffineTransform结构体定义

struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
1
2
3
4
5
它其实表示的是一个矩阵:

因为最后一列总是是(0,0,1),所以有用的信息就是前面两列。对一个view进行仿射变化就相当于对view上的每个点做一个乘法,结果就是:

a表示x水平方向的缩放,tx表示x水平方向的偏移
d表示y垂直方向的缩放,ty表示y垂直方向的偏移
如果b和c不为零的话,那么视图肯定发生了旋转,旋转角度这样计算:tan(angle) = b / a

如果这样:

这个就是没有变化的最初的样子。

CGAffineTransform操作API
//还原
CGAffineTransformIdentity

//位移仿射 ---- 理解为平移 (CGFloat tx,CGFloat ty)
CGAffineTransformMakeTranslation
CGAffineTransformTranslate
//旋转仿射 ---- 理解为旋转 (CGFloat angle)
CGAffineTransformMakeRotation
CGAffineTransformRotate
//缩放仿射 --- 理解缩放大小 (CGFloat sx, CGFloat sy)
CGAffineTransformMakeScale
CGAffineTransformScale
1
2
3
4
5
6
7
8
9
10
11
12
CGAffineTransform操作的数学本质

CGPoint转换公式

矩阵乘法运算原理演示

2.4.2 CATransform3D操作API
//还原
CATransform3DIdentity

//位移3D仿射 ==> (CGFloat tx, CGFloat ty, CGFloat tz)
CATransform3DMakeTranslation
CATransform3DTranslation
//旋转3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeRotation
CATransform3DRotation
//缩放3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale
CATransform3DScale
//叠加3D仿射效果
CATransform3DConcat
//仿射基础3D方法,可以直接做效果叠加
CGAffineTransformMake (sx,shx,shy,sy,tx,ty)
//检查是否有做过仿射3D效果 == ((CATransform3D t))
CATransform3DIsIdentity(transform)
//检查2个3D仿射效果是否相同
CATransform3DEqualToTransform(transform1,transform2)
//3D仿射效果反转(反效果,比如原来扩大,就变成缩小)
CATransform3DInvert(transform)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.4.3 CATransform3D与CGAffineTransform相互转换API
//将一个CGAffinrTransform转化为CATransform3D
CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);
//判断一个CATransform3D是否可以转换为CAAffineTransformbool
CATransform3DIsAffine (CATransform3D t);
//将CATransform3D转换为CGAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
1
2
3
4
5
6
2.5 “组合动画” 与 CGAffineTransformConcat
2.5.1 连接设置多个属性组合成一个动画
连接设置两个以上属性的动画,可以先调用含有 formMake 的API,然后再调用只含 form 的API。例如,这样:

alertView.transform = CGAffineTransformMakeScale(.25, .25);
alertView.transform = CGAffineTransformTranslate(alertView.transform, 0, 600);
1
2
2.5.2 利用CGAffineTransformConcat设置组合动画
另外,可以直接利用 CGAffineTransformConcat 来组合多种含有 formMake 的形变API。

CGAffineTransform viewTransform = CGAffineTransformConcat(CGAffineTransformMakeScale(.25, .25), CGAffineTransformMakeTranslation(0, 600));
alertView.transform = viewTransform;
1
2
关于组合3D形变也有相应的API — CATransform3DConcat,关于3D形变下一篇会专门介绍。

CGAffineTransformConcat 组合多种形变动画小例子

  • (void)viewDidAppear: (BOOL)animated {
    /// 初始化动画开始前label的位置
    CGFloat offset = label1.frame.size.height * 0.5;

    label1.transform = CGAffineTransformConcat(
    CGAffineTransformMakeScale(0, 0),
    CGAffineTransformTranslate(0, -offset)
    );
    label1.alpha = 0;
    [UIView animateWithDuration: 3. animations: ^ {
    /// 还原label1的变换状态并形变和偏移label2
    label1.transform = CGAffineTransformIdentifier;
    label1.transform = CGAffineTransformConcat(
    CGAffineTransformMakeScale(0, 0),
    CGAffineTransformTranslate(0, offset)
    );
    label1.alpha = 1;
    label2.alpha = 0;
    }];
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    组合变换的本质
    CGAffineTransformConcat的数学本质是将括号内代表的若干变换的系数矩阵进行相乘。

另一种组合变换
基于已有的CGAffineTransform连续追加新的CGAffineTransform:

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 0.5f, 0.5f);
transform = CGAffineTransformRotate(transform, 30.0f/180.0f*M_PI);
transform = CGAffineTransformTranslate(transform, 200.0f, 0.0f);
layerView.layer.affineTransform = transform;
1
2
3
4
5
2.6 动画后将属性还原
当我们改变过一个view.transform属性或者view.layer.transform的时候需要恢复默认状态的话,记得先把他 们重置为:

view.transform = CGAffineTransformIdentity;
view.layer.transform = CATransform3DIdentity;
1
2
2.7 注意点: transform对frame的影响
官方文档上关于transform属性的说明:

Changes to this property can be animated. However, if the transform
property contains a non-identity transform, the value of the frame
property is undefined and should not be modified. In that case, you
can reposition the view using the center property and adjust the size
using the bounds property instead.

如果在程序中改变了某个控件的transform,那么请不要使用这个控件的frame计算 子控件 的布局,应该使用bounds+center代替。

  1. CAAnimation核心动画
    CAAnimation——所有动画对象的父类

3.1 设置动画的一种语法形式
addAnimation

/**

  • 抖动效果
    */
    -(void)shakeAnimation{
    CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];//在这里@"transform.rotation"==@"transform.rotation.z"
    NSValue value1 = [NSNumber numberWithFloat:-M_PI/1804];
    NSValue value2 = [NSNumber numberWithFloat:M_PI/1804];
    NSValue value3 = [NSNumber numberWithFloat:-M_PI/1804];
    anima.values = @[value1,value2,value3];
    anima.repeatCount = MAXFLOAT;

    [_demoView.layer addAnimation:anima forKey:@"shakeAnimation"];
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    3.2 CAAnimation继承结构
    CAAnimation{
    CAPropertyAnimation{
    CABasicAnimation{
    CASpringAnimation
    }
    CAKeyframeAnimation
    }
    CATransition
    CAAnimationGroup
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类

3.3 CAAnimation类的属性
带*号代表来自CAMediaTiming协议的属性)

*duration:动画的持续时间
*repeatCount:重复次数,无限循环可以设置HUGE_VALF或者MAXFLOAT
*repeatDuration:重复时间
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
*fillMode:决定当前对象在非active时间段的行为。比如动画开始之前或者动画结束之后
*beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为
CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间
timingFunction:速度控制函数,控制动画运行的节奏
delegate:动画代理
3.4 几个重要属性值
removedOnCompletion属性值
CAAnimation——动画填充模式

默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards

fillMode属性值
CAAnimation——控制恢复到动画执行前

要想fillMode有效,最好设置removedOnCompletion = NO

kCAFillModeRemoved
这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
kCAFillModeBackwards
在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。
kCAFillModeBoth
这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态
如果 fillMode = kCAFillModeForwards 同时 removedOnComletion = NO ,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。

timingFunction属性值
CAAnimation——动画速度控制函数

kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。

  1. CABasicAnimation
    基本动画,是CAPropertyAnimation的子类

4.1 特别属性说明:
keyPath: 要改变的属性名称(传字符串)
fromValue: keyPath相应属性的初始值
toValue: keyPath相应属性的结束值
4.2 keyPath可以是哪些值
CATransform3D{
//rotation旋转
transform.rotation.x
transform.rotation.y
transform.rotation.z

//scale缩放
transform.scale.x
transform.scale.y
transform.scale.z

//translation平移
transform.translation.x
transform.translation.y
transform.translation.z

}

CGPoint{
position
position.x
position.y
}

CGRect{
bounds
bounds.size
bounds.size.width
bounds.size.height

bounds.origin
bounds.origin.x
bounds.origin.y

}

property{
opacity
backgroundColor
cornerRadius
borderWidth
contents

Shadow{
    shadowColor
    shadowOffset
    shadowOpacity
    shadowRadius
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
4.3 举例
缩放动画 – transform.scale

//心脏缩放动画
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; //选中的这个keyPath就是缩放
scaleAnimation.fromValue = [NSNumber numberWithDouble:0.5]; //一开始时是0.5的大小
scaleAnimation.toValue = [NSNumber numberWithDouble:1.5]; //结束时是1.5的大小
scaleAnimation.duration = 1; //设置时间
scaleAnimation.repeatCount = MAXFLOAT; //重复次数
[_heartImageView.layer addAnimation:scaleAnimation forKey:@"CQScale"]; //添加动画
1
2
3
4
5
6
7
旋转动画 – transform.rotation.z

//风车旋转动画
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.fromValue = [NSNumber numberWithDouble:0.f];
rotationAnimation.toValue = [NSNumber numberWithDouble:2 * M_PI];
rotationAnimation.duration = 2.f;
rotationAnimation.repeatCount = MAXFLOAT;
[_fengcheImageView.layer addAnimation:rotationAnimation forKey:@"CQRotation"];
1
2
3
4
5
6
7
平移动画 – position.x/position.y

//平移动画
CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
positionAnimation.fromValue = [NSNumber numberWithDouble:0.f];
positionAnimation.toValue = [NSNumber numberWithDouble:SCREEN_WIDTH];
positionAnimation.duration = 2;
positionAnimation.repeatCount = MAXFLOAT;
[_arrowImageView.layer addAnimation:positionAnimation forKey:@"CQPosition"];
1
2
3
4
5
6
7

  1. CAKeyframeAnimation关键帧动画
    5.1 参数数组形式
    //根据values移动的动画
    CAKeyframeAnimation *catKeyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    CGPoint originalPoint = self.catImageView.layer.frame.origin;
    CGFloat distance = 50;
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + distance, originalPoint.y + distance)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + 2 * distance, originalPoint.y + distance)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + 2 * distance, originalPoint.y + 2 * distance)];
    NSValue *value4 = [NSValue valueWithCGPoint:originalPoint];
    catKeyAnimation.values = @[value4, value1, value2, value3, value4];
    catKeyAnimation.duration = 2;
    catKeyAnimation.repeatCount = MAXFLOAT;
    catKeyAnimation.removedOnCompletion = NO;
    [self.catImageView.layer addAnimation:catKeyAnimation forKey:nil];
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    5.2 path形式
    //指定path
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 200, 200)];
    //指定path的动画
    UIBezierPath *path2 = [UIBezierPath bezierPath];
    [path2 moveToPoint:CGPointMake(100, 100)];
    [path2 addLineToPoint:CGPointMake(100, 200)];
    [path2 addLineToPoint:CGPointMake(200, 200)];
    [path2 addLineToPoint:CGPointMake(200, 100)];
    [path2 addLineToPoint:CGPointMake(100, 100)];
    CAKeyframeAnimation *penguinAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    penguinAnimation.path = path2.CGPath;
    penguinAnimation.duration = 2;
    penguinAnimation.repeatCount = MAXFLOAT;
    penguinAnimation.removedOnCompletion = NO;
    [self.penguinImageView.layer addAnimation:penguinAnimation forKey:nil];
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  2. 组动画
    6.1 组动画
    上面单一动画的情况在实际开发中实际比较少,更多的时候是组合这些动画:创建不同类型的动画对象,设置好它们的参数,然后把这些动画对象存进数组,传进组动画对象的animations属性中去。

6.2 示例
//创建组动画
CAAnimationGroup animationGroup = [CAAnimationGroup animation];
animationGroup.duration = 3;
animationGroup.repeatCount = MAXFLOAT;
animationGroup.removedOnCompletion = NO;
/
beginTime 可以分别设置每个动画的beginTime来控制组动画中每个动画的触发时间,时间不能够超过动画的时间,默认都为0.f */

//缩放动画
CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
animation1.values = @[[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.5],[NSNumber numberWithFloat:1.0]];
animation1.beginTime = 0.f;

//按照圆弧移动动画
CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(300, 200)];
[bezierPath addQuadCurveToPoint:CGPointMake(200, 300) controlPoint:CGPointMake(300, 300)];
[bezierPath addQuadCurveToPoint:CGPointMake(100, 200) controlPoint:CGPointMake(100, 300)];
[bezierPath addQuadCurveToPoint:CGPointMake(200, 100) controlPoint:CGPointMake(100, 100)];
[bezierPath addQuadCurveToPoint:CGPointMake(300, 200) controlPoint:CGPointMake(300, 100)];
animation2.path = bezierPath.CGPath;
animation2.beginTime = 0.f;

//透明度动画
CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation3.fromValue = [NSNumber numberWithDouble:0.0];
animation3.toValue = [NSNumber numberWithDouble:1.0];
animation3.beginTime = 0.f;

//添加组动画
animationGroup.animations = @[animation1, animation2,animation3];
[_penguinImageView.layer addAnimation:animationGroup forKey:nil];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

  1. 贝塞尔曲线
    前面关键帧动画章节提到了贝塞尔曲线,这个曲线很有用,在iOS开发中有两种形式可用:CGMutablePathRef和UIBezierPath,均可以通过制定控制点数组的形式唯一确定曲线,也可以通过矩形内切椭圆唯一确定曲线。下面是两者的例子:

7.1 CGMutablePathRef
通过 关键点曲线连接 唯一确定

// 贝塞尔曲线关键帧
// 设置路径, 绘制贝塞尔曲线
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 200, 200); // 起始点
CGPathAddCurveToPoint(path, NULL, 100, 300, 300, 500, 200, 600);
// CGPathAddCurveToPoint(path, NULL, 控制点1.x, 控制点1.y, 控制点2.x, 控制点2.y, 终点.x, 终点.y);
// 设置path属性
keyframeAnimation.path = path;
CGPathRelease(path);

// 设置其他属性
keyframeAnimation.duration = 4;
keyframeAnimation.beginTime = CACurrentMediaTime() + 1; // 设置延迟2秒执行, 不设置这个属性, 默认直接执行
// 3. 添加动画到图层, 会自动执行
[_layer addAnimation:keyframeAnimation forKey:@"GGKeyframeAnimation"];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.2 UIBezierPath
通过 矩形内切椭圆 唯一确定

CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(SCREEN_WIDTH/2-100, SCREEN_HEIGHT/2-100, 200, 200)];
anima.path = path.CGPath;
anima.duration = 2.0f;
[_demoView.layer addAnimation:anima forKey:@"pathAnimation"];
1
2
3
4
5
通过 关键点直线连接 唯一确定

-(void)pathAnimation2{

//创建path
UIBezierPath *path = [UIBezierPath bezierPath];
//设置线宽
path.lineWidth = 3;
//线条拐角
path.lineCapStyle = kCGLineCapRound;
//终点处理
path.lineJoinStyle = kCGLineJoinRound;
//多条直线
[path moveToPoint:(CGPoint){0, SCREEN_HEIGHT/2-50}];
[path addLineToPoint:(CGPoint){SCREEN_WIDTH/3, SCREEN_HEIGHT/2-50}];
[path addLineToPoint:(CGPoint){SCREEN_WIDTH/3, SCREEN_HEIGHT/2+50}];
[path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2+50}];
[path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2-50}];
[path addLineToPoint:(CGPoint){SCREEN_WIDTH, SCREEN_HEIGHT/2-50}];

// [path closePath];

CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
anima.path = path.CGPath;
anima.duration = 2.0f;
anima.fillMode = kCAFillModeForwards;
anima.removedOnCompletion = NO;
anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[_demoView.layer addAnimation:anima forKey:@"pathAnimation"];

}

作者:H.A.N
来源:CSDN
原文:https://blog.csdn.net/u010960265/article/details/80930068
版权声明:本文为博主原创文章,转载请附上博文链接!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容