核心动画
1. 核心动画基本概念
1> 核心动画(Core Animation)是一组非常强大的动画处理API,使用它能够做出非常绚丽的动画效果,而且往往事半功倍
2> 使用它需要先添加QuartzCore.framework和引用对应的框架<QuartzCore/QuartzCore.h>。Xcode5就不用在添加了,会自动添加
3> 开发步骤
1) 初始化一个动画对象(CAAnimation)
2) 设置一些相关属性。CALayer中很多属性都可以通过CAAnimation属性来设置动画效果,包括:opacity、position、transform、bounds、contents等(可以在API文档中搜索:CALayer Animatable Properties)
3) 添加动画对象到层(CALayer)中,开始执行动画
a) 通过调用CALayer的addAnimation:forKey:添加动画到层(CALayer)中,这样就能触发动画了
b) 通过调用removeAnimationForKey可以停止层中的动画。
3) Core Animation的动画执行过程都是在后台执行的,不会阻塞主线程
4> CAAnimation继承结构

2. CAAnimation
1> CAAnimation是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体子类
2> 属性说明:(红色代表来自CAMediaTiming协议的属性)
1) duration: 动画持续时间
2) repeatCount: 重复次数,无限循环可以使用HUGE_VALF或者MAXFLOAT
3) repeatDuration: 每次重复的时间间隔
4) removeOnCompletion: 动画执行完毕后就从图层上移除,图形会恢复到动画执行之前的状态,默认为YES。如果想让图形显示动画执行后的状态,需要将其设置为NO,另外还要设置fillMode为kCAFillModeForwards
5) fillMode: 决定当前对象在非active时间段的行为。比如动画开始之前,或者开始之后。
6) beginTime: 用来设置动画延迟执行时间,若需延迟2s,就设置为CACurrentMediaTime() + 2 , CACurrentMediaTime()为图层的当前时间
7) timingFunction: 速度控制函数,控制动画运行节奏
8) delegate: 动画代理
3> 动画填充模式(fillMode)
1) fillMode属性值(如果想要fillMode有效,最好设置removeOnCompletion为NO)
2) kCAFillModeRemoved: 这个是默认值,动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态。
3) kCAFillModeForwards: 当动画结束后,layer会一直保持在动画最后的状态
4) kCAFillModeBackwards:在动画开始之前,只需将动画加入了一个Layer,layer便立即进入动画的初始化状态并等待动画开始。
5) kCAFillModeBoth:这个其实就是上面两个的合成,动画加入layer后,但没有开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后状态。
4> 速度控制函数(CAMediaTimingFunction)
1) kCAMediaTimingFunctionLiner(线性):匀速,给用户一个相对静态的感觉。
2) kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
3) kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
4) kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。
5> 动画代理方法
CAAnimation在分类中定义了代理方法:
@interface NSObject (CAAnimationDelegate)
#pragma mark 动画开始
- (void) animationDidStart:(CAAnimation *) anim;
#pragma mark 动画结束
- (void) animationDidStop:(CAAnimation *) anim finished:(BOOL) flag;
@end
6> CALayer上动画的暂停和恢复方法
#pragma mark 暂停CALayer的动画
- (void) pauseLayer:(CALayer*)layer{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
// 让CALayer的时间停止运动
layer.speed = 0.0f;
// 让CALayer的时间停留在pauseTime这个时间
layer.timeOffset = pausedTime;
}
#pragma mark 恢复CALayer的动画
- (void) resumeLayer:(CALayer*)layer{
CFTimeInterval pausedTime = layer.timeOffset;
//1. 让CALayer的时间继续行走
layer.speed = 1.0f;
//2. 取消上次记录的停留时间
layer.timeOffset = 0.0f;
//3. 取消上次设置的时间
layer.beginTime = 0.0f;
//4. 计算暂停的时间(这里也可以用CACurentMediaTime() - pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] = pausedTime;
//5. 设置相对于夫坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
3. CAPropertyAnimation
1> CAPropertyAnimation是CAAnimation的子类,也是个抽象类,要想创建动画对象,就要使用它的两个子类(CABasicAnimation、CAKeyframeAnimation)
2> 属性说明:
1) keyPath:通过指定CALayer的属性名称,从而达到动画效果:比如指定@"position",执行平移的效果
4. CABasicAnimation
1> CApropertyAnimation的子类
2> 属性说明:
1) fromValue: keyPath相应属性的初始值
2) toValue:keyPath相应属性的结束值
3> 动画过程说明:
1) 随着动画的进行,在时长为duration的时间内,kayPath相对应属性的值从fromValue渐渐变到toValue
2) keyPath内容是CALayer的可动画Animatable属性
3) 如果fillMode = KCAFillModeForwards同时removeOnComletion=NO,那么在动画执行完毕后,图层会保留动画执行后的状态。但实质上,图层的属性值还是动画执行前的初始值,并没有正真被改变
【示例1 - 使用CABasicAnimation完成平移、缩放、旋转动作】
#import <UIKit/UIKit.h> @interface MainViewController : UIViewController #pragma mark - 动画的暂停和恢复 #pragma mark 暂停动画 -(void) pauseAnimation; #pragma mark 恢复动画 -(void) resumeAnimation; @end
#import "MainViewController.h" @interface MainViewController () @property (weak,nonatomic) UIView *myView; @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; UIView *myView = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 100, 100)]; [myView setBackgroundColor:[UIColor redColor]]; [self.view addSubview:myView]; self.myView = myView; } #pragma mark -动画代理方法 #pragma mark 动画开始(极少用) -(void) animationDidStart:(CAAnimation *)anim{ NSLog(@"动画开始"); } #pragma mark 动画结束(通常在动画结束后,设置动画后续处理) -(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ NSLog(@"动画结束"); NSString *animationType = [anim valueForKeyPath:@"animationType"]; if ([animationType isEqualToString:@"translationTo"]) { //1. 通过键值取出需要移动到的目标点 CGPoint targetPoint = [[anim valueForKeyPath:@"targetPoint"]CGPointValue]; //2. 设置myView的坐标点 [self.myView setCenter:targetPoint]; } NSLog(@"%@",NSStringFromCGPoint(self.myView.layer.position)); } #pragma mark - touch 事件 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; if ([touch view] == self.myView) { NSLog(@"点击了myView"); } //1. 平移动画 //[self translationTo:location]; //2. 缩放动画 //[self scaleAnimation]; //3. 旋转动画 CAAnimation *anim = [self.myView.layer animationForKey:@"rotationAnim"]; if (anim) { if (self.myView.layer.speed == 0) { [self resumeAnimation]; }else{ //[self.myView.layer removeAllAnimations]; [self pauseAnimation]; } }else{ [self rotationAnimation]; } } #pragma mark - 动画的暂停和恢复 #pragma mark 暂停动画 -(void) pauseAnimation{ // 1. 取出当前动画的时间点,就是要暂停的时间点 CFTimeInterval pausedTime = [self.myView.layer convertTime:CACurrentMediaTime() fromLayer:nil]; // 2. 设置动画的时间偏移量,指定时间偏移量的目的是让动画定格在该时间点 [self.myView.layer setTimeOffset:pausedTime]; // 3. 将动画的速度置为0,动画默认速度是1 [self.myView.layer setSpeed:0.0f]; } #pragma mark 恢复动画 -(void) resumeAnimation{ //1. 取出动画的暂停点 CFTimeInterval pausedTime = [self.myView.layer timeOffset]; //2. 将动画偏移量清空 [self.myView.layer setTimeOffset:0.0f]; //3. 将动画速度还原为1 [self.myView.layer setSpeed:1.0f]; //4. 根据媒体时间准确的计算出动画延迟执行时间 // [self.myView.layer convertTime:CACurrentMediaTime() fromLayer:nil]这个会有点延迟,原因目前还不知道 CFTimeInterval beginTime = CACurrentMediaTime() - pausedTime; //5. 设置动画延迟时间 /** 说明:1) 动画在第0秒的时候开始动 2) 在第5秒的时候暂停了,即anim.timeOffset = 5; 3) 在第8秒的时候恢复运动,5~8相隔3秒,anim.beginTime属性是延迟多少秒执行, 这样anim.beginTime = 3; 距上次暂停的时间开始推迟3秒执行,正好是当前时间第8秒 **/ [self.myView.layer setBeginTime:beginTime]; } #pragma mark - CABasic动画 #pragma mark 平移动画到指定点 -(void) translationTo:(CGPoint) location{ //1. 实例化动画 // 如果没有指定图层的锚点(定位点)postion默认为UIView的中心点 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; //2. 设置动画属性 //1) fromValue(myView的当前坐标) && toValue [anim setToValue:[NSValue valueWithCGPoint:location]]; //2) 动画时长2秒 [anim setDuration:2.0f]; //3) 设置代理 [anim setDelegate:self]; //4) 让动画停留在目标位置 /** 通过设置动画在完成后不删除,以及向前填充,可以做到动画结束后UIView看起来停留在目标位置 但实质上没有改变UIView的坐标,即frame不会发生变化 **/ [anim setRemovedOnCompletion:NO]; [anim setFillMode:kCAFillModeForwards]; //5) 要修正动画结束后UIView的坐标点,可以利用setValue方法 [anim setValue:[NSValue valueWithCGPoint:location] forKeyPath:@"targetPoint"]; [anim setValue:@"translationTo" forKeyPath:@"animationType"]; //6) 将动画添加到图层 // 将动画添加到图层后,系统会按照定义好的属性开始动画,通常程序员不再与动画进行交互 [self.myView.layer addAnimation:anim forKey:nil]; } #pragma mark 旋转动画 -(void) rotationAnimation{ //1. 实例化对象 // 默认沿着Z轴旋转 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; //2. 设置属性 //1) fromValue && toValue [anim setToValue:@(2 * M_PI)]; //2) 设置无限循环 [anim setDuration:2.0f]; //3) 设置循环次数,无限循环赋值为HUGE_VALF [anim setRepeatCount:HUGE_VALF]; //4) 动画结束后,不要删除图层 [anim setRemovedOnCompletion:NO]; //3. 添加到layer [self.myView.layer addAnimation:anim forKey:@"rotationAnim"]; } #pragma mark 缩放动画 -(void) scaleAnimation{ //1. 实例化动画 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; //2. 设置属性 //1) fromValue && toValue //默认为1.0 //[anim setFromValue:@(1.0)]; [anim setToValue:@(0.5)]; //2) 自动还原 [anim setAutoreverses:YES]; //3) 设置时长 [anim setDuration:2.0f]; //3. 将动画添加到层 [self.myView.layer addAnimation:anim forKey:nil]; } @end
#import "AppDelegate.h" #import "MainViewController.h" @interface AppDelegate () @property (weak,nonatomic) MainViewController *mainController; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; MainViewController *controller = [[MainViewController alloc]init]; self.window.rootViewController = controller; self.mainController = controller; [self.window makeKeyAndVisible]; return YES; } #pragma mark 失去焦点 - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"失去焦点"); [self.mainController pauseAnimation]; } #pragma mark 进入后台 - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"进入后台"); } #pragma mark 进入前台 - (void)applicationWillEnterForeground:(UIApplication *)application { NSLog(@"进入前台"); } #pragma mark 获取焦点 - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"获取焦点"); [self.mainController resumeAnimation]; } - (void)applicationWillTerminate:(UIApplication *)application { } @end
5. CAKeyframeAnimation
1> 关键帧动画(CAKeyframeAnimation),也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:
1) CABasicAnimation只能从一个数值(fromValue)变到另外一个数值(toValue),而CAKeyframeAnimation可以使用数组(NSArray)保存动画数值。
2> 属性说明:
1) values:上述的NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
2) path: 可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path值对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略
3) keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围0~1.0。keyTimes中每一个时间值都对应values中的每一个帧。如果没有设置keyTimes,那么values中的每一个帧的时间都是平分的。
3> CABasicAnimation可以看做只有2个关键帧的CAKeyframeAnimation.
4> 计算模式(calculationMode)
4.1> 在关键帧动画中还有一个非常重要的参数,那便是计算模式(calculationMode),主要是针对values中每一个帧内容为一个坐标点的情况,也就是对anchorPointposition进行的动画。
4.2> 当在平面坐标系中有多个点的时候,???这些点可以是离散的,也可以是直线相连的
4.3> calculationMode目前提供如下几种模式:
1) kCAAnimationLinear:默认值,表示当关键帧为坐标点的时候,关键帧之间直接直线相连进行插值计算。
2) kCAAnimationDiscrete:离散的,不进行插值计算。所有关键帧都逐个依次显示。
3) kCAAnimationCubic:对于关键帧为坐标点的关键帧进行圆滑曲线相连后进行插值计算,这里的主要目的是使动画运行的更加圆滑
4) kCAAnimationCubicPaced:看这个名字就知道和kCAAnimationCubic一定有联系,其实就是在kCAAnimation的基础上使得动画运行的更加均匀。指定了该属性,keyTimes以及timingFunctions也将失效。
【示例 2 - 关键帧动画】
#import <UIKit/UIKit.h> @interface AnimationView : UIView #pragma mark -关键帧动画 #pragma mark 摇晃动画 - (void)shakeAnimation; #pragma mark 贝塞尔曲线,两个控制点 - (void)moveCurveWithDuration:(CFTimeInterval)duration to:(CGPoint)to; #pragma mark 贝塞尔曲线,一个控制点 - (void)moveQuadCurveWithDuration:(CFTimeInterval)duration to:(CGPoint)to; #pragma mark 按照矩形路径平移动画 // 移动的矩形是以当前点为矩形的一个顶点,目标点为矩形的对脚顶点 - (void)moveRectWithDuration:(CFTimeInterval)duration to:(CGPoint)to; #pragma mark 使用随机中心点控制动画平移 -(void) moveWithDuration:(CFTimeInterval)duration to:(CGPoint)to controlPointCount:(NSInteger)count; #pragma mark 移动到目标点(当前坐标->(0,0)->location) -(void) transformTo:(CGPoint) location; @end
#import "AnimationView.h" @implementation AnimationView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setBackgroundColor:[UIColor blueColor]]; } return self; } #pragma mark - 私有方法 #pragma mark 随机生成屏幕的上点 -(CGPoint) randomPoint{ CGFloat width = self.superview.bounds.size.width; CGFloat height = self.superview.bounds.size.height; CGFloat x = arc4random_uniform(width); CGFloat y = arc4random_uniform(height); return CGPointMake(x, y); } #pragma mark - 关键帧动画 #pragma mark 摇晃动画 // 课下练习动画的暂停和恢复 - (void)shakeAnimation { // 1. 实例化关键帧动画 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"]; // 晃动 // [anim setDuration:0.5f]; // 1> 角度 CGFloat angel = M_PI_4 / 12.0; [anim setValues:@[@(angel), @(-angel), @(angel)]]; // 2> 循环晃 [anim setRepeatCount:HUGE_VALF]; // 3. 将动画添加到图层 [self.layer addAnimation:anim forKey:nil]; } #pragma mark 贝塞尔曲线,两个控制点 - (void)moveCurveWithDuration:(CFTimeInterval)duration to:(CGPoint)to { // 1. 实例化关键帧动画 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; // 2. 设置路径 [anim setDuration:duration]; // 中间的控制点使用屏幕上得随机点 CGPoint cp1 = [self randomPoint]; CGPoint cp2 = [self randomPoint]; CGMutablePathRef path = CGPathCreateMutable(); // 设置起始点 CGPathMoveToPoint(path, NULL, self.center.x, self.center.y); // 添加带一个控制点的贝塞尔曲线 CGPathAddCurveToPoint(path, NULL, cp1.x, cp1.y, cp2.x, cp2.y, to.x, to.y); [anim setPath:path]; CGPathRelease(path); // 5) 设置键值记录目标位置,以便动画结束后,修正位置 [anim setValue:@"translationTo" forKey:@"animationType"]; [anim setValue:[NSValue valueWithCGPoint:to] forKey:@"targetPoint"]; [anim setDelegate:self]; // 3. 将动画添加到图层 [self.layer addAnimation:anim forKey:nil]; } #pragma mark 贝塞尔曲线,一个控制点 - (void)moveQuadCurveWithDuration:(CFTimeInterval)duration to:(CGPoint)to { // 1. 实例化关键帧动画 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; // 2. 设置路径 [anim setDuration:duration]; // 中间的控制点使用屏幕上得随机点 CGPoint cp = [self randomPoint]; CGMutablePathRef path = CGPathCreateMutable(); // 设置起始点 CGPathMoveToPoint(path, NULL, self.center.x, self.center.y); // 添加带一个控制点的贝塞尔曲线 CGPathAddQuadCurveToPoint(path, NULL, cp.x, cp.y, to.x, to.y); [anim setPath:path]; CGPathRelease(path); // 5) 设置键值记录目标位置,以便动画结束后,修正位置 [anim setValue:@"translationTo" forKey:@"animationType"]; [anim setValue:[NSValue valueWithCGPoint:to] forKey:@"targetPoint"]; [anim setDelegate:self]; // 3. 将动画添加到图层 [self.layer addAnimation:anim forKey:nil]; } #pragma mark 按照矩形路径平移动画 // 移动的矩形是以当前点为矩形的一个顶点,目标点为矩形的对脚顶点 - (void)moveRectWithDuration:(CFTimeInterval)duration to:(CGPoint)to{ //1. 实例化动画 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; //2. 设置属性,按照矩形一定,需要使用到路径 //1) 创建路径 CGMutablePathRef path = CGPathCreateMutable(); //2) 矩形起点、宽、高 CGFloat width = to.x - self.center.x; CGFloat height = to.y - self.center.y; CGRect rect = CGRectMake(self.center.x, self.center.y, width, height); CGPathAddRect(path, NULL, rect); //3) 将路径添加到动画 [anim setPath:path]; //4) 释放路径 CGPathRelease(path); //3. 将动画添加到层 [anim setDuration:duration]; //3. 添加到层 [self.layer addAnimation:anim forKey:nil]; } #pragma mark 使用随机中心点控制动画平移 -(void) moveWithDuration:(CFTimeInterval)duration to:(CGPoint)to controlPointCount:(NSInteger)cpCount{ CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; NSMutableArray *array = [NSMutableArray arrayWithCapacity:cpCount + 2]; [array addObject:[NSValue valueWithCGPoint:self.center]]; for (int i = 0; i < cpCount; i++) { [array addObject:[NSValue valueWithCGPoint:[self randomPoint]]]; } [array addObject:[NSValue valueWithCGPoint:to]]; [anim setValues:array]; [anim setDuration:duration]; [self.layer addAnimation:anim forKey:nil]; } #pragma mark 移动到目标点(当前坐标->(0,0)->location) -(void) transformTo:(CGPoint) location{ //1. 实例化动画 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; //2. 设置属性 //1) 设置Values NSValue *p1 = [NSValue valueWithCGPoint:self.center]; NSValue *p2 = [NSValue valueWithCGPoint:CGPointMake(0, 0)]; NSValue *p3 = [NSValue valueWithCGPoint:location]; [anim setValues:@[p1,p2,p3]]; //2) 设置时长 [anim setDuration:2.0f]; //3) 设置代理 [anim setDelegate:self]; //4) 动画结束后,不要从图层移除 [anim setRemovedOnCompletion:NO]; [anim setFillMode:kCAFillModeForwards]; //5) 设置Value值,用于修正动画结束后UIView的坐标 [anim setValue:@"transformTo" forKey:@"animationType"]; [anim setValue:p3 forKey:@"targetPoint"]; //3. 添加到层 [self.layer addAnimation:anim forKey:nil]; } @end
#import <UIKit/UIKit.h> @interface MainViewController : UIViewController @end
#import "MainViewController.h" #import "AnimationView.h" @interface MainViewController () @property (weak,nonatomic) AnimationView *myView; @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; AnimationView *myView = [[AnimationView alloc]initWithFrame:CGRectMake(50, 50, 100, 100)]; [self.view addSubview:myView]; self.myView = myView; UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)]; [self.view addGestureRecognizer:tapRecognizer]; } #pragma mark -动画代理方法 -(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ if (anim) { NSString *animationType = [anim valueForKey:@"animationType" ]; if ([animationType isEqualToString:@"transformTo"]) { CGPoint targetPoint = [[anim valueForKey:@"targetPoint"]CGPointValue]; self.myView.center = targetPoint; } } NSLog(@"%@",NSStringFromCGPoint(self.myView.center)); } #pragma mark - 手势识别器 #pragma mark 点击手势识别器 -(void) tapAction:(UITapGestureRecognizer *) recognizer{ CGPoint location = [recognizer locationInView:self.view]; //1) 移动到目标点(当前坐标->(0,0)->location) //[self.myView transformTo:location]; //2) 使用随机中心点控制动画平移 //[self.myView moveWithDuration:5.0f to:location controlPointCount:5]; //3) 按照矩形路径平移动画 //[self.myView moveRectWithDuration:2.0f to:location]; //4) 贝塞尔曲线,一个控制点 //[self.myView moveQuadCurveWithDuration:2.0f to:location]; //5) 贝塞尔曲线,两个控制点 //[self.myView moveCurveWithDuration:2.0f to:location]; //6) 摇晃动画 //[self.myView shakeAnimation]; } @end
6. CAAnimationGroup
1> 动画组(CAAnimationGroup),是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup添加到层后,组中所有动画将并发执行
2> 属性说明
1) animations:用来保存一组动画的NSArray
默认情况下,一组动画对象是同时运行的,也可以设置动画对象的beginTime属性来更改动画的开始时间。
7. 转场动画
浙公网安备 33010602011771号