iOS基础-动画效果的总结--(CALayer,CoreAnimation))

粉骨碎身全不怕, 要留清白在人间!<小拳石>

动画的思维导图

基础知识:
iOS能够实现动画的方式:(如上图)

  • UIView基础实现方式一
  • UIView基础实现方式二
  • CoreAnimation实现方式

动画的效果简述:

  • 传达状态
  • 提高用户对直接操作的感知
  • 帮助用户可视化操作的结果

UIVIew 的基础动画:

  • UIKit直接将动画继承到UIView类中, 当内部的一些属性发生改变时, UIView将为这些改变提供动画支持.
  • 执行动画的工作由UIView类自动完成, 但希望在执行动画时通知视图, 为此需要将改变属性的代码放在[UIView beginAnimations: nil context: nil][UIView commitAnimations]之间.

代码部分详细介绍相关属性


CALayer基本介绍:

  • CALayer负责绘制, 提供UIView需要展示的内容, 不能交互
  • UIView负责交互,显示CALayer绘制的内容
  • CALayer(层)是屏幕上的一个矩形区域, 在每一个UIView中都包含一个根
  • CALayer, 在UIView上的所以视觉效果都是在这个Layer上进行的.

1: 在 iOS 中, 我们能看见的, 例如按钮, 文本, 标签, 输入框, 等等 都是 UIView
2: 其实 UIView 之所以能显示在屏幕上, 完全是因为它内部的一个图层, 在创建 UIView 对象的时候, UIView 内部会自动创建一个图层就是(CALayer 对象), 通过 UIView 的 layer 属性就可以访问这个层
3: 当 UIView 需要显示到屏幕上时, 会调用 drawRect: 方法进行绘图, 并且将所有的绘制内容在自己的图层上绘制, 给图层绘制完毕后, 系统将会拷贝图层到屏幕上, 完成 UIView 的显示
4: UIVIew 本身是不具备显示功能的, 真正拥有显示功能的是里面的 layer 层
5: 通过 UIView 的图层, 可以调整 UIView 的一些界面属性, 例如阴影 圆角 边框 颜色

CALayer外形特征主要包括:

  • 层的大小尺寸
  • 背景色
  • 内容(可以填充图片或者使用Core Graphics绘制的内容)
  • 积习是否使用圆角
  • 矩形是否有阴影

CALayer常用属性:
与UIView动画相比, CoreAnimation能够实现更多复杂, 好看, 高效的动画效果:

  • 阴影, 圆角, 带颜色的边框
  • 3D变换

  • 透明遮罩

  • 多级非线性动画

  • CALayer的坐标系统比UIView多了一个anchorPoint属性
    anchorPoint锚点相对自身bounds来说,默认值为(0.5,0.5),即是anchorPoint的默认值在layer的中心点,它的值在0~1之间


    简单图示锚点

CoreAnimation动画

  • CoreAnimation动画位于iOS框架的Media层

  • CoreAnimation动画实现需要添加QuartzCore.Framework

  • CoreAnimation基本上是Layer Animation

  • CABasicAnimation基本单一类型的动画

  • CAKeyframeAnimation 帧动画, 主要操作属性与keyPath 和 values值组合

  • CAAnimationGroup组合动画, 操作属性: animations将CAAnimation类型的动画加入数组, FIFO队列的方式执行

1: 核心动画的基本概念

① core Animation, 核心动画, 是一组非常强大的动画处理 API, 可以用少量的代码, 实现强大的功能
② core Animation, 可以用在 Mac OS 和 iOS 两个平台
③ core Animation, 动画的执行过程, 都是在后台操作的, 所以不会阻塞主线程
④ core Animation, 是直接操作 CALayer 层的, 并不是 UIView

2: CAAnimation
① 所有动画的父类, 负责控制动画的持续时间和速度, 他是一个抽象的类, 不能直接使用, 应该使用他的子类
② 属性说明:

  • duration: 动画的持续时间
  • repeatCount: 动画的重复次数
  • repeatDuration: 重复时间
  • removeOnCompletion (BOOL): 默认为 YES, 表示动画执行完毕后就从图层上移除, 图形会恢复到执行之前的状态. 如果想要保持执行之后的状态, 那就设置 NO, 但是, 还需要设置 fillMode 值为 kCAFillModeForwards
  • fillModel: 决定当前对象在非活动的时间段的行为, 比如动画开始前或者动画结束之后 (想要 fillMode 有效, 最好将removeOnCompletion = 0);
  • kCAFillModeRemove:
    默认值也就是当前动画开始前和动画结束后, 动画对 layer 都没有影响, 动画结束后, layer 会恢复之前的状态
  • kCAFillModeForwards:
    当前结束动画后, layer 会一直保持最后的状态
  • kCAFillModeBackwards:
    在动画开始之前, 只需要将动画加入一个 layer, layer 便立即进入动画的初始状态并等待动画的开始.
  • kCAFillModeBoth: 就是上面两个 kCAFillModeForwards 和kCAFillModeBackwards 的合成
  • beginTime: 可以用来设置动画的延迟时间, 若想设置延迟 2秒, 那么就设置 CACurrentMediaTime() + 2 CACurrentMediaTime()图层当前的时间
  • timeFuncation: 速度控制函数 控制动画运行的节奏

---> CAMediaTimingFunctionLinear (线性): 匀速, 给你一个相对静态的感觉
---> CAMediaTimingFunctionEaseIn (淡入): 动画缓慢进入, 然后加速离开
---> CAMediaTimingFunctionEaseOut (淡出): 动画全速进入, 然后减速到达目的地
---> CAMediaTimingFunctionEaseInEaseOut (淡入淡出)

③ CAAnimation 的子类

  • CABasicAnimation
  • CALeyFrameAnimation
  • CAAnimationGroup
  • CASpringAnimation

④ 属性说明

  • keypath: 通过制定 CALayer 的一个属性名称为 keypath(NSString 类型) , 并且对 CALayer 这个属性值进行修改, 达到相应的动画效果, 比如, 制定@"postion"为 keypath , 就相当于修改了 CALayer 的 poison 属性的值,达到平移的动画效果.
  • 下面的代码部分会对这个 关建路径支持结构字段 进行相应的总结
关键路径支持的部分字段说明
  • 关键路径支持的部分字段补充说明

margin = 布局
zPosition = 翻转
backgroundColor = 背景颜色
cornerRadius = 圆角
borderWidth = 边框宽
bounds = 大小
contents = 内容
contentsRect = 内容大小
cornerRadius = 圆角
frame = 大小位置
hidden = 显示隐藏
mask 遮罩
masksToBounds
opacity 不透明的
position 位置
shadowColor 阴影颜色
shadowOffset 阴影偏移量
shadowOpacity 阴影不透明的
shadowRadius 阴影半径
transform.scale = 比例转换
transform.scale.x =以 x轴 比例转换
transform.scale.y = 以 y轴 比例转换
transform.rotation.z = 平面圆形旋转

3: 关键帧动画 与 CABasicAnimation 的区别
① CABasicAnimation只能从一个数值(fromvalue) 变换到另外一个数值 (tovaule)
② 关键帧动画, 会使用一个 NSArray 保存这些数值

4: 动画组
① 属性说明:

  • animations: 用来保存一组动画对象NSArray
  • 默认情况下, 一组动画对象是同时运动的, 也可以通过设置动画的 beginTime 属性来更改动画的开始时间

5: 转场动画 -------- CATransition: --------------
CATransition: 用于做转场动画效果, 能够为 layer 层提供移出屏幕和移入屏幕的动画效果
① 动画属性:

  • type: 动画的过渡效果

类型字符串 效果说明
fade 交叉淡化过渡
push 新视图把旧视图推出去
moveIn 新视图移到旧视图上面
reveal 将旧视图移开,显示下面的新视图
cube 立方体翻转效果
oglFlip 上下左右翻转效果
suckEffect 收缩效果,像一块布被抽走
rippleEffect 水滴效果
pageCurl 向上翻页效果
pageUnCurl 向下翻页效果

cameraIrisHollowOpen 相机镜头打开效果
cameraIrisHollowClose 相机镜头关闭效果

  • subtype: 动画的过渡方向
  • startProgress: 动画的起点(在整个动画的百分比)
  • endProgress: 动画的终点

UIView 的基础动画 代码总结
实例1: 自定义一个属性 MyLabel (UILabel)类型的 展示的是 UIView 的动画效果, 在一个触发方法里面实现动画,我这里写在 TouchBegin 里面.

//1. 创建一个动画
[UIView beginAnimations:nil context:nil];
//2. 动画延迟设置
[UIView setAnimationDelay:1];
//3. 给动画添加代理(不遵循代理协议, 也能实现代理方法)
[UIView setAnimationDelegate:self];
//4. 给动画添加方法(动画结束后执行)
[UIView setAnimationDidStopSelector:@selector(stopAc)];
//5. 动画持续时间(完成动画所需时间)
[UIView setAnimationDuration:2];
//6. 设置动画是否会做一次反向的执行  (等会属性里面再说)
[UIView setAnimationRepeatAutoreverses:YES];
//7. 设置动画移动的新位置
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
//8. 开始提交动画 (解释可以看下面)
[UIView commitAnimations];
基础动画--**这个 MyLabel 从开始的位置移动到新位置,设置了反向执行 YES 所以到达新位置后又反向移动了最后才来到新位置**

总结一下这里涉及的方法: 均是 UIView 的类方法

  • 第 1个方法: 动画马上开始:begin
+(void)beginAnimations:(NSString*)animationID context:(void *)context{}

# 参数1: animationID 作为动画的标示使用, 可以方便移除动画操作
# 参数2:  context 动画的设置 自定义的一些动画数据,这些数据将发送给动画的代理方法 默认 nil
  • 最后 1 个方法: commit
# 这个方法  就是提交动画 也是标记动画的内容已经编辑好了  可以使用效果了
+ (void)commitAnimations

在这两个方法之间就我们进行,动画相关的一些设置,下面是一些设置的方法

# 设置代理 及其 方法不需要设置遵循代理方法  默认 nil 没有代理
+ (void)setAnimationDelegate:(nullable id)delegate;                          
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;                
+ (void)setAnimationDidStopSelector:(nullable SEL)selector; 

# 设置动画持续时间     默认 = 0.2            
+ (void)setAnimationDuration:(NSTimeInterval)duration;  
# 设置动画的延迟时间 默认是不延迟 就是0.00            
+ (void)setAnimationDelay:(NSTimeInterval)delay;    
# 设置动画的开始时间     default = now ([NSDate date])        
+ (void)setAnimationStartDate:(NSDate *)startDate;   

# 设置动画的曲线方式(动画的总体变化的时间曲线:开始快最后慢,开始慢最后快,最后慢,均匀线性)  默认default = UIViewAnimationCurveEaseInOut
/*typedef NS_ENUM(NSInteger, UIViewAnimationCurve){
    UIViewAnimationCurveEaseInOut,    
    UIViewAnimationCurveEaseIn,     
    UIViewAnimationCurveEaseOut,     
    UIViewAnimationCurveLinear
  };
*/            
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;              

# 动画的重复次数 default = 0.0.  
+ (void)setAnimationRepeatCount:(float)repeatCount;                 

# 设置动画是否做一次反向的执行。
/*如果设置为YES:动画将执行:动画初始状态->动画->动画完成状态->动画->动画初始状态 。
如果设置为NO:默认值*/
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;    

# 设置动画的开始状态
/*
YES : 第一个动画正在 执行时候, 另一个动画恰好开始, 这样第一个动画的当前状态, 就是另一个动画的开始状态
NO: 第一个达到完成状态, 下一个动画才开始执行动画的效果
*/
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;  

# 设置视图view的过渡效果, transition指定过渡类型, cache设置YES代表使用视图缓存,性能较好
/*
UIView官方提供五种动画效果供大家使用,分别为:
UIViewAnimationTransitionNone    不使用动画
UIViewAnimationTransitionFlipFromLeft    从左向右旋转翻页
UIViewAnimationTransitionFlipFromRight    从右向左旋转翻页
UIViewAnimationTransitionCurlUp    卷曲翻页,从下往上
UIViewAnimationTransitionCurlDown    卷曲翻页,从上往下
*/
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; 

# 设置view是否有动画效果
/*
YES: 默认有动画的能力
NO: 关闭动画效果
效果关闭并不会对 UI 的改变有什么影响只是不会 "动画" 了而已, 其他的大小什么属性依然有效的
*/  
+ (void)setAnimationsEnabled:(BOOL)enabled; 

# 判断当前的动画效果是否关闭了                  
+ (BOOL)areAnimationsEnabled;

通过 UIView 的几个 Block 方法进行动画设置

  • // 实现动画 的 Block1

参数1 : Duration 动画持续时间 Block 里面就写你要实现的效果(位置的改变等)

[UIView animateWithDuration:2 animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
}];


- // 实现动画 的 Block2 
```code
# 参数比上面多一个 动画结束后的操作
    [UIView animateWithDuration:2 animations:^{
        self.MyLabel.frame = CGRectMake(100, 100, 200, 200);
    } completion:^(BOOL finished) {
        NSLog(@"动画结束的操作可以写这里");
    }];```

- // 实现动画 的 Block3
 ```code   
   /* 
      参数1: Duration: 动画持续时间
      参数2: delay: 延迟时间
      参数3: options: 枚举值 动画的效果类型*/
  [UIView animateWithDuration:2 delay:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
        } completion:^(BOOL finished) {
NSLog(@"结束了%d", finished); 
}];```

-  //实现动画的Block4 弹簧效果
```code    
 /*
     Spring: 模拟弹簧弹跳的效果
     参数: Damping:阻尼 0-1 阻尼越小动画越明显
     参数: initialSpringVelocity : 动画初始变化速度
     参数: options  转变的风格  枚举值
*/
 [UIView animateWithDuration:10 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:15 options:(UIViewAnimationOptionCurveEaseInOut) animations:^{
        self.MyLabel.center = CGPointMake(self.view.center.x, 100);
    } completion:^(BOOL finished) {
        NSLog(@"弹簧效果结束");
 }];```

- //实现动画的Block5  关键帧动画 也就是里面有好几个动画进行转变
```code    
    /*
    Duration:持续时间
    delay: 延迟时间
     options: 枚举值  动画的风格
     */
[UIView animateKeyframesWithDuration:3   delay:0 options:(UIViewKeyframeAnimationOptionRepeat) animations:^{
/*
参数1: RelativeStartTime:  相对的开始时间
参数2: relativeDuration:相对持续时间
*/
         [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.5 animations:^{
            self.MyLabel.center = self.view.center;
        }];
        [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.3 animations:^{
            self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
        }];
           [UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.3 animations:^{
            self.MyLabel.frame = CGRectMake(100, 400, 100, 100);
        }];     
    } completion:^(BOOL finished) {
        NSLog(@"结束了");
    }];

  • CAAnimation 的子类
    ------------ CABasicAnimation -----------------
# 1: 创建  以字段为   旋转变换
    CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
# 动画效果的初始值
    basic.fromValue = @0;
# 动画效果变化的结束值 (绝对值)  这里就是旋转的角度从多少转到多少度
    basic.toValue = @(2*M_PI);
# 动画执行时间
    basic.duration = 5;
# Layer 动画需要天加到 layer 上    forkey 我们可以写上我们标记的动画属性    
[self.MyLabel.layer addAnimation:basic forKey:@"transform.rotation"];
这个效果就是旋转360°(顺时针-->初始值比结束值小),

--------- CAKeyFramAnimation 关键帧动画--------

 // 创建  以关键字段   位置变化
    CAKeyframeAnimation *keyframe = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//  建几个动画的位置
    CGPoint p1 = CGPointMake(0, 0);
    CGPoint p2 = CGPointMake(0, 400);
    CGPoint p3 = CGPointMake(400, 100);
    CGPoint p4 = CGPointMake(100, 200);
    CGPoint p5 = CGPointMake(200, 300);
    NSValue *v1 = [NSValue valueWithCGPoint:p1];
    NSValue *v2 = [NSValue valueWithCGPoint:p2];
    NSValue *v3 = [NSValue valueWithCGPoint:p3];
    NSValue *v4 = [NSValue valueWithCGPoint:p4];
    NSValue *v5 = [NSValue valueWithCGPoint:p5];
     //属性 values :  数组对象 里面的元素称为"keyFrame"(关键帧), 动画对象会在指定的时间里 (duration). 依次显示values 数组中的每一个关键帧
    keyframe.values = @[v1,v2,v3,v4,v5];
    keyframe.duration = 10;
    // 每一帧的时间,  每一帧的时间为比例的累加计算  取值范围 0-1,没有设置的话 每一帧的时间是平分的
    keyframe.keyTimes = @[@0.1,@0.1,@0.1,@0.1];
   [self.MyLabel.layer addAnimation:keyframe forKey:@"系统保留关键字"];
关键帧动画的演示

--------- CAAnimationGroup 动画组--------

// 创建
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 10;
// 把上面两个动画加到这个动画组里面
group.animations = @[basic,keyframe];
[self.MyLabel.layer addAnimation:group forKey:@"同上"];

--------------- CASpringAnimation 模拟弹簧动画效果--------

     // 创建一个弹簧动画   结构关键字段  意思是竖直方向上  模拟弹簧  
CASpringAnimation *spring  = [CASpringAnimation animationWithKeyPath:@"position.y"];
    // 设置动画效果的初始值
    spring.fromValue = @50;
    // 设置动画的结束值
    spring.toValue = @10;
    // 阻尼系数
    spring.damping = 0.1;
    // 刚度系数: (劲度系数 / 弹性系数): 系数越大,形变的产生的力越大, 运动越快
    spring.stiffness = 10;
   // 质量: 影响图层运动时候的惯性, 质量越大弹簧拉伸和压缩的幅度越大 (动画的幅度,波动变大)
    spring.mass = 1;
    // 初识速率: 动画视图的初识速度大小
    // 速率为正时候, 速度方向与运动方向一致, 否则相仿.
    spring.initialVelocity = 1;
    // settlingDuration 结算时间,预估弹簧动画到停住的时间的估算, 根据当前动画的各个参数估算, 通常弹簧动画的估算时间使用结算时间比较准确
    spring.duration = spring.settlingDuration;
  [self.MyLabel.layer addAnimation:spring forKey:@"弹簧"];
弹簧效果动画

---------- CATransition -------

// 创建
CATransition *trans = [CATransition animation];
  // 效果
  trans.type = @"pageCurl";
  // 开始位置 (0-1)
  trans.startProgress = 0;
  // 结束位置 (0-1)
  trans.endProgress = 1;
  // 效果方向
  trans.subtype = kCATransitionFromLeft;
   // 重复次数
  trans.repeatCount = 10;
  // 持续时间
  trans.duration = 3;
   [self.MyView.layer addAnimation:trans forKey:@"11"];

转场动画效果图

实例: 切换图片参考;

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

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,321评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,001评论 5 13
  • Core Animation Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,...
    45b645c5912e阅读 2,968评论 0 21
  • 前言 本文只要描述了iOS中的Core Animation(核心动画:隐式动画、显示动画)、贝塞尔曲线、UIVie...
    GitHubPorter阅读 3,538评论 7 11
  • 书写的很好,翻译的也棒!感谢译者,感谢感谢! iOS-Core-Animation-Advanced-Techni...
    钱嘘嘘阅读 2,217评论 0 6