iOS:动画(18-10-15更)
目录
1、UIView Animation
1-1、UIView Animation(基本使用)
1-2、UIView Animation(转场动画)
2、CATransaction(Layer版的UIView Animation)
3、CAAnimation
3-0、CALayer移除、取Animation。
3-1、- CAAnimation(base基类)
3-2、 | - CAPropertyAnimation(属性动画)
3-3、 | | - CABasicAnimation(基础动画)
3-4、 | | | - CASpringAnimation(弹簧动画 iOS 9.0+!)
3-5、 | | - CAKeyframeAnimation(关键帧、路径动画)
3-6、 | - CATransition(转场动画)
3-7、 | - CAAnimationGroup(动画组)
3-附录、旋转 >= 180 度
...
N-1、UIDynamicAnimator(物理引擎)
N、粒子动画
其他
1、模态视图转场动画
2、自定义转场动画(相当于快照当前屏幕)
3、动画所需的变换
3-1、view:CGAffineTransform(缩放、位移、旋转。二维变换)
3-2、layer:CATransform3D(缩放、位移、旋转。三维变换)
4、设置缺省动画(隐式动画)
0、写在前面
1)、当view做变换后,frame的宽高为所需最小的(外切)矩形,不再是原来尺寸,原来的可用bounds获取。
如4:3的宽高旋转90度,frame的宽高就变成3:4。bounds,还是原来的4:3。
2)、view.layer.anchorPoint ,影响动画效果
3)、旋转,>=180度,会反方向旋转(自动寻找最短路径?),解决方案,参照 “3、CAAnimation” -> “3-附录、旋转 >= 180 度”。
4)、UIImageView 有自带的动画属性、方法:
// 本地动画图片帧 添加到 数组
for (int i=0; i<7; i++)
{NSString *imgName = [NSString stringWithFormat:@“images_%d”,i+1];UIImage *image = [UIImage imageNamed:imgName];[arr addObject:image];
}// 动画图片帧的数组,动画时间,动画次数
animationImageView.animationImages = arr;
animationImageView.animationDuration = time;
animationImageView.animationRepeatCount = count;
[animationImageView startAnimating];
补充:1、无法获得结束的代理,要么监听 animating 属性,要么用 CAKeyframeAnimation 动画替换。
2、设置的 animationDuration 不精确,如果用延时等待结束,再操作该imageView,记得要先停止动画 stopAnimating,否则,有时候正常,有时候修改图片,又被动画覆盖掉,差几毫秒的可能。
1、UIView Animation
1-1、UIView Animation(基本使用)
1)、原始的,非Block。
//动画名、内容
[UIView beginAnimations:@"id100" context:@"animation1"];
//时长2秒
[UIView setAnimationDuration:2.0];
//动画速度
// UIViewAnimationCurveEaseInOut, // 慢入、慢出
// UIViewAnimationCurveEaseIn, // 慢入
// UIViewAnimationCurveEaseOut, // 慢出
// UIViewAnimationCurveLinear, // 匀速
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
//设置代理
[UIView setAnimationDelegate:self];
//动画将要开始SEL
[UIView setAnimationWillStartSelector:@selector(animationWillStart:context:)];
//动画将要结束SEL
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
//提交动画
[UIView commitAnimations];//签代理后,才能实现SEL的方法(方法名随意,参数个数也随意,分别少于2/3个的时候,只收到前面几个参数,多于它的参数,后面参数空,有用过C的回调函数,应该会比较熟悉)
//开始动画时的方法
-(void)animationWillStart:(NSString *)animationID context:(void *)context
{NSLog(@"动画开始");
}
//结束动画时的方法
-(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{//可以判断ID,做连续动画NSLog(@"动画结束");
}
//自己取名
-(void)theAnimationStop:(NSString *)animationID thecontext:(void *)theContext context:(void *)context2
{
NSLog(@"%@,%@,%@",animationID,theContext,context2);
}
2)、Block
// 基础
[UIView animateWithDuration:1.0 animations:^{// 新的值
}];// 嵌套,做连续动画
[UIView animateWithDuration:2.0 animations:^{self.cyanVIew.frame = CGRectMake(100, 400, 100, 100);
} completion:^(BOOL finished) {[UIView animateWithDuration:2.0 animations:^{self.cyanVIew.frame = CGRectMake(100, 100, 100, 100);}];
}];// 可以设置一些 延时、动画速度 可选项等。
[UIView animateWithDuration:2.0delay:0.0options:UIViewAnimationOptionCurveEaseInOutanimations:^{// 新的值} completion:^(BOOL finished) {// 动画完成,可以再嵌套动画}];// 弹簧/缓冲 动画(7.0以后)
[UIView animateWithDuration:2.0delay:0.0usingSpringWithDamping:0.5 // 震荡周期(0-1)initialSpringVelocity:5.0 // 初始速度options:UIViewAnimationOptionCurveEaseInanimations:^{// 新的值} completion:^(BOOL finished) {// 动画完成,可以再嵌套动画}];// 不懂(7.0以后)
[UIView animateKeyframesWithDuration:1.0delay:0.0options:UIViewKeyframeAnimationOptionCalculationModeCubicanimations:^{// 新的值} completion:^(BOOL finished) {// 动画完成,可以再嵌套动画}];
1-2、UIView Animation(转场动画)
1)、UIView Animation 方法
// 参数cache,
// YES为截图后再转场,减轻系统负担,动画更流畅,
// NO为一起动画,如需要边转场边动画的效果// UIViewAnimationTransitionNone,
// UIViewAnimationTransitionFlipFromLeft, //左边下翻效果(X信,好友历史说说,查看详情)
// UIViewAnimationTransitionFlipFromRight, //右边下翻效果
// UIViewAnimationTransitionCurlUp, //上翻日历效果
// UIViewAnimationTransitionCurlDown, //下盖日历效果//1、导航栏转场
[UIView animateWithDuration:2.0 animations:^{[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:YES];[self.navigationController pushViewController:vc animated:NO];
}];//2、普通View转场,把当前View放在最底层,最好大小全相同,不然动画效果很尴尬
[UIView animateWithDuration:2.0 animations:^{//转场动画[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:bgView cache:YES];//最上面的View放到最下面exchangeSubviewAtIndex:withSubviewAtIndex:[bgView sendSubviewToBack:[[bgView subviews] lastObject]];
}];
2)、UIView transition 方法
// 1、以当前View的范围,对子fronView、子backView做动画[UIView transitionFromView:self.fronViewtoView:self.backViewduration:1.0options:UIViewAnimationOptionTransitionCurlUpcompletion:^(BOOL finished) {}];// 2、以View的范围做动画[UIView transitionWithView:self.imageViewduration:1.0options:UIViewAnimationOptionTransitionCurlUpanimations:^{UIImage *currentImage = self.imageView.image;NSUInteger index = [self.images indexOfObject:currentImage];index = (index + 1) % [self.images count];self.imageView.image = self.images[index];} completion:^(BOOL finished) {}];
2、CATransaction(Layer版的UIView Animation)
// 开始[CATransaction begin];// 时长,默认0.25秒[CATransaction setAnimationDuration:1.0];// 慢入、快出等。[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];// 完成 或 删除 后的block[CATransaction setCompletionBlock:^{}];// 提交[CATransaction commit];// =============== 未知 ===============[CATransaction flush];[CATransaction lock];[CATransaction unlock];// =============== 禁止layer自带的动画 ===============[CATransaction begin];[CATransaction setDisableActions:YES];// 改变Layer的属性[CATransaction commit];
3、CAAnimation
3-0、CALayer移除、取Animation。
[self.testLayer animationForKey:@"test_animation"];[self.testLayer animationKeys];[self.testLayer removeAnimationForKey:@"test_animation"];[self.testLayer removeAllAnimations];
3-1、CAAnimation
1)、主要属性:removedOnCompletion 完成移除、timingFunction 慢入快出等、delegate 代理 。
// 完成动画自动移除。默认YES。NO需要手动移除,否则会占用内存
animation.removedOnCompletion = NO;// 动画速度(慢入、慢出)
// kCAMediaTimingFunctionLinear //匀速
// kCAMediaTimingFunctionEaseIn //慢入
// kCAMediaTimingFunctionEaseOut //慢出
// kCAMediaTimingFunctionEaseInEaseOut //慢入慢出
// kCAMediaTimingFunctionDefault //匀速,不过有点快
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];// 代理
animation.delegate = self;- (void)animationDidStart:(CAAnimation *)anim{
}
// flag = YES 完成动画,flag = NO animation没做完被remove了
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
}
补充:如同一个VC、View 多个动画,代理也无法分清。
因为,代理的参数传进来是深拷贝过的,就算比对self.CAAnimation和代理的anim,地址不同,也会比对失败。
但是,CAAnimation本身类似一个字典,所以,可以随意设值,来匹配。
// 标注哪个Layer的动画
[animation setValue:testLayer forKey:@"handLayer"];- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{CALayer *testLayer = [anim valueForKey:@"handLayer"];CABasicAnimation *baseAnim = (CABasicAnimation*)anim;// 需要禁掉layer自带的属性变化动画,View没有。// 不禁的话,变化完,会跳回原来的,再做自带的动画变化。[CATransaction begin];[CATransaction setDisableActions:YES];testLayer.transform = [baseAnim.toValue CATransform3DValue];[CATransaction commit];
}
2)、主要协议<CAMediaTiming>:duration 每次动画时间、repeatCount 重复次数等。重复次数、重复时长二选一。
// 动画延迟开始时间animation.beginTime = CACurrentMediaTime() + 2.0;// 动画周期(时间)animation.duration = 3.0;// 动画速度(快进、慢放)animation.speed = 2.0;// 动画起始偏移(偏移量的位置比例为timeOffset / duration,与speed无关。如果播放次数为1次,那么动画就从偏移量开始,播放到尾 - 头 - 偏移量)animation.timeOffset = 1.0;// 动画重复次数(不包含倒放的次数)animation.repeatCount = INFINITY;// 动画重复时间(包含倒放的时间)animation.repeatDuration = INFINITY;// 动画播完倒放到原来的状态(时长一样)animation.autoreverses = YES;// 动画更新属性时间:动画 前、后、前后、移除
// kCAFillModeForwards // 开始:无动作,等待beginTime到达。 结束:保持结束位置。
// kCAFillModeBackwards // 开始:迅速到达动画开始位置、状态,等待beginTime到达。结束:返回动画前位置。
// kCAFillModeBoth // 开始:迅速到达动画开始位置、状态,等待beginTime到达。结束:保持结束位置。
// kCAFillModeRemoved // 开始:无动作,等待beginTime到达。 结束:返回动画前位置。animation.fillMode = kCAFillModeBoth;
补充:1、动画添加上去,就不能修改了,所以如果要暂停动画,快近等,需要对图层设置。
2、不会影响到子图层:duration、repeatCount、repeatDuration。
3、会影响到子图层 :beginTime、timeOffset、speed。
4、当 layer.speed = 0,不断改变timeOffset,可以手动动画。
5、不同图层时间转换
- (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(CALayer *)l;
- (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l;
3-2、CAPropertyAnimation
1)、主要属性:keyPath 变换的属性。
// 属性animation.keyPath = @"transform";
3-3、CABasicAnimation(基础动画)
1)、例子。CABasicAnimation 只有 fromValue、byValue、toValue 三个属性,其他是继承。
CABasicAnimation *animation = [CABasicAnimation animation];// 动画的属性animation.keyPath = @"transform";// 初始值:不设置、nil 默认为 当前值animation.fromValue = [NSValue valueWithCATransform3D:fromTransform];// 相对值:相对当前的增量animation.byValue = [NSValue valueWithCATransform3D:byTransform];// 绝对值:变成什么样animation.toValue = [NSValue valueWithCATransform3D:toTransform];// 动画时间animation.duration = 0.5;// 添加动画[self.testLayer addAnimation:animation forKey:@"test_transform"];
补充:开始动画,会突然跳到开始的Value。
结束动画,会突然跳到最开始的Value。
所以需要在开始、结束手动调整到变化的属性,不然很突兀。
参照 “2-1)、CAAnimation” -> “1)、主要属性:delegate 代理” -> “补充”。
3-4、CASpringAnimation(弹簧动画 iOS 9.0+!)
CASpringAnimation *animation = [CASpringAnimation animation];// 质量 > 0 ,默认 1(值越大,震荡范围越大、越久)animation.mass = 1;// 弹簧刚度系数 > 0 ,默认 100 (值越大,震荡范围越大、越快)animation.stiffness = 100;// 阻尼系数 >= 0 ,默认 10(阻力)animation.damping = 10;// 初始速度animation.initialVelocity = 5.0;// 动画时间animation.duration = animation.settlingDuration;// 继承CABaseAnimationanimation.keyPath = @"position";animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 200)];animation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 100)];[self.testLayer addAnimation:animation forKey:@"xx"];
3-5、CAKeyframeAnimation(关键帧动画)
1)、关键帧动画,主要属性:values(帧)、keyTimes(帧对应的时间点)、calculationMode(连续、离散等)。
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];animation.keyPath = @"position";animation.duration = 10.0;animation.values = @[[NSValue valueWithCGPoint:CGPointMake(50, 50)],[NSValue valueWithCGPoint:CGPointMake(100, 180)],[NSValue valueWithCGPoint:CGPointMake(150, 120)],[NSValue valueWithCGPoint:CGPointMake(50,50)]];animation.keyTimes = @[@0.0,@0.3,@0.8,@1.0];// 动画速度(默认控制全局,慢入慢出)// 1、控制每个关键帧的切换。如每次切换 慢入快出 ,像呼吸灯。个数少1。
// CAMediaTimingFunction *fn = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseIn];
// animation.timingFunctions = @[fn, fn, fn];// 2、控制整体动画。如用贝塞尔曲线,决定加速度。
// animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:1 :0 :0.75 :1];// 默认线性// kCAAnimationLinear// 离散// kCAAnimationDiscrete// kCAAnimationPaced// kCAAnimationCubic// kCAAnimationCubicPacedanimation.calculationMode = kCAAnimationLinear;[self.testLayer addAnimation:animation forKey:nil];
补充:同CABasicAnimation,如果变化初值、结束值不同原来的,会跳变。
初值:最好相同。
结束值:1、要么相同值。2、要么变化完修改属性。
再补充:可以通过下面方法,获取系统的 慢入慢出等动画,加速度的贝塞尔曲线控制点。
CAMediaTimingFunction *function = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];CGPoint controlPoint1, controlPoint2;[function getControlPointAtIndex:1 values:(float *)&controlPoint1];[function getControlPointAtIndex:2 values:(float *)&controlPoint2];
2)、路径动画。主要属性:path 路径、rotationMode 设置后layer跟着旋转。
#if 0//创建可变路径CGMutablePathRef path = CGPathCreateMutable();//变换CGAffineTransform transform = CGAffineTransformMakeTranslation(0, 200);//椭圆(变换可空)CGPathAddEllipseInRect(path, &transform, CGRectMake(50, 100, 300, 300));
#endif// 路径UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 100, 300, 300)];CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];animation.keyPath = @"position";animation.duration = 10.0;// 路径animation.path = path.CGPath;// layer的内容跟着旋转animation.rotationMode = kCAAnimationRotateAutoReverse;[self.testLayer addAnimation:animation forKey:nil];
补充:如要画轨迹,用同一个path配合 CAShapeLayer ,参照《iOS:绘图》 -> “1、UIBezierPath(贝塞尔曲线)” -> “2)、”
3-6、CATransition(转场动画)
1)、动画设置。主要属性:type 动画效果、subtype 动画方向。
CATransition *animation = [CATransition animation];animation.duration = 1.5;//动画类型// kCATransitionFade //淡入// kCATransitionMoveIn //覆盖// kCATransitionPush //推// kCATransitionReveal //掀起,相对覆盖//以下为私有API// @"cube" //立方体(某宝的AR切换)// @"suckEffect" //吮吸// @"oglFlip" //翻转(某信,好友历史说说,查看详情)// @"rippleEffect" //波纹// @"pageCurl" //日历上翻// @"pageUnCurl" //日历下盖// @"cameraIrisHollowOpen" //相机打开// @"cameraIrisHollowClose" //相机关闭animation.type = @"cube";//动画方向// kCATransitionFromRight //从右边// kCATransitionFromLeft //从左边// kCATransitionFromTop //从上面// kCATransitionFromBottom //从下面animation.subtype = kCATransitionFromLeft;// 从动画的0.0开始
// animation.startProgress = 0.0;// 到动画的1.0结束
// animation.endProgress = 1.0;
2)、添加
2-1)、普通View的切换动画
// 添加动画到普通的View
[bgView.layer addAnimation:animation forKey:@"view_transition"];
// 把最上面的View放到最底层,一般转场可能就2层相互转换,也可用
exchangeSubviewAtIndex:withSubviewAtIndex:
[bgView sendSubviewToBack:[[bgView subviews] lastObject]];
2-2)、导航栏动画
// 添加动画到导航栏
[self.navigationController.view.layer addAnimation:animation forKey:@"navi_transition"];
[self.navigationController pushViewController:vc animated:NO];
3)、tabbar动画
// 设置代理
tbVC.delegate = self;- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{// 当前的VC IndexNSLog(@"--%ld",tabBarController.selectedIndex);return YES;
}- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{// 点中的VC IndexNSLog(@"==%ld",tabBarController.selectedIndex);// 每次切换都加动画CATransition *animation = [CATransition animation];animation.type = kCATransitionPush;// 判断从左还是从右切换if (/*当前VC的Index和点中的VC的Index比较*/) {animation.subtype = kCATransitionFromLeft;}else{animation.subtype = kCATransitionFromRight;}// 添加动画[tbVC.view.layer addAnimation:animation forKey:@"tabbar_transition"];
}
3-7、CAAnimationGroup(动画组)
1)、只有一个属性:animations 动画组。例子效果:边运动边变换颜色。
// 路径动画UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 100, 300, 300)];CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];animation1.keyPath = @"position";animation1.path = path.CGPath;// 关键帧动画CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animation];animation2.keyPath = @"backgroundColor";animation2.values = @[(__bridge id)[UIColor blueColor].CGColor,(__bridge id)[UIColor orangeColor].CGColor,(__bridge id)[UIColor greenColor].CGColor,(__bridge id)[UIColor blueColor].CGColor];// ===========================================================================================// 动画组CAAnimationGroup *group = [CAAnimationGroup animation];group.duration = 10.0;group.animations = @[animation1,animation2];[self.testLayer addAnimation:group forKey:@"test_group"];
3-附录、旋转 >= 180 度
1)、CAKeyframeAnimation
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];animation.keyPath = @"transform";animation.duration = 2.0;animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0, 0, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0, 0, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeRotation(3*M_PI_2, 0, 0, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeRotation(2*M_PI, 0, 0, 1)],];animation.calculationMode = kCAAnimationLinear;[self.testLayer addAnimation:animation forKey:nil];
2)、CABasicAnimation(虚拟属性transform.rotation)
CABasicAnimation *animation = [CABasicAnimation animation];animation.keyPath = @"transform.rotation";animation.duration = 2.0;animation.byValue = @(M_PI * 2);[self.testLayer addAnimation:animation forKey:@"test_transform.rotation"];
N-1、UIDynamicAnimator(物理引擎)
写在前面:
行为都继承UIDynamicBehavior,所以,有运动中Block
behavior.action = ^{};
物理引擎添加各种行为
//动画作用的局域UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];...//添加行为[animator addBehavior:behavior];
1)、UIGravityBehavior(重力行为)
//重力行为(只创建不设置属性也可以,默认角度M_PI_2、加速度量级为1的重力)UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[cyanView]];//重力角度// gravity.angle = M_PI_4;//重力量级(加速度)// gravity.magnitude = 0.1;//重力角度 和 重力量级(加速度)// [gravity setAngle:M_PI_4 magnitude:0.1];//重力矢量 0.0 - 1.0//设置后,上面的角度、加速度量级都失效,如果矢量超过1加速度也会变大。gravity.gravityDirection = CGVectorMake(1, 1);
2)、UIPushBehavior(推力行为)
// UIPushBehaviorModeContinuous, //持续作用力
// UIPushBehaviorModeInstantaneous //推一把UIPushBehavior *push = [[UIPushBehavior alloc]initWithItems:@[redLabel] mode:UIPushBehaviorModeInstantaneous];//推力角度
// push.angle = M_PI_4;//推力量级
// push.magnitude = 1;//推力角度 和 推力量级
// [push setAngle:M_PI_4 magnitude:0.1];//推力矢量 0.0 - 1.0//设置后,上面的角度、量级都失效,如果矢量超过1速度也会变大。push.pushDirection = CGVectorMake(1, 1);//设置该行为下的item 推力的偏离量,效果如打桌球的边角,或是滚动的球[push setTargetOffsetFromCenter:UIOffsetMake(15, 0) forItem:redLabel];[animator addBehavior:push];
3)、UICollisionBehavior(碰撞行为)
//碰撞行为UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[cyanView,redLabel]];//获取 相互碰撞的items 、 items相互碰撞点 、 碰撞的边界ID// collision.collisionDelegate = self;//碰撞方式// UICollisionBehaviorModeItems //items相互碰撞// UICollisionBehaviorModeBoundaries //items只与边界碰撞// UICollisionBehaviorModeEverything //items、边界都碰撞collision.collisionMode = UICollisionBehaviorModeEverything;//碰撞边界//1、转换物理引擎UIDynamicAnimator的Reference边界成碰撞的边界collision.translatesReferenceBoundsIntoBoundary = YES;//2、转换物理引擎UIDynamicAnimator的Reference边界成碰撞的边界,且设置有内边距// [collision setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(100, 60, 50, 60)];//3、设置边界为一个屏幕的内切圆路径// [collision addBoundaryWithIdentifier:@"test" forPath:[UIBezierPath bezierPathWithOvalInRect:SCREEN_BOUNDS]];//4、设置边界为为一条直线。想要一个封闭的空间,至少要添加3次,即三角形// [collision addBoundaryWithIdentifier:@"test" fromPoint:CGPointMake(50, 500) toPoint:CGPointMake(300, 500)];
4)、UISnapBehavior(迅速移动行为)
//创建迅速移动行为UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:cyanView snapToPoint:point];//更新移动点snap.snapPoint = CGPointMake(50, 50);//值越小 抖动越厉害 0.0 - 1.0snap.damping = 0.5;
5)、UIAttachmentBehavior(吸附行为)
1)、旧版功能,已测试,没问题。
1、如果同时加重力,就想摆钟一样,吸附距离就像一根绳子(类似划断绳子,礼物下落的小游戏)。
2、如果实时用触摸点设置锚点,就是拖到哪移动哪,同时带有震荡效果(如果不需要震荡效果,简单的transform都能实现。)
//1、item 吸附到点 AnchorUIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:cyanView attachedToAnchor:[touches.anyObject locationInView:self]];//2、item 吸附到点 Anchor,且item的中心点有x、y偏移
// UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:cyanView offsetFromCenter:UIOffsetMake(15, 15) attachedToAnchor:[touches.anyObject locationInView:self]];//3、item 吸附到 item,同时向对方移动
// UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:cyanView attachedToItem:redLabel];//4、item 吸附到 item,同时向对方移动,且有x、y偏移
// UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:cyanView offsetFromCenter:UIOffsetMake(0, 0) attachedToItem:redLabel offsetFromCenter:UIOffsetMake(0, 0)];//长度必须设置。item吸附过来时候,item的center 距离 锚点 距离 / 两个item的center的距离 / 两个item的center,再加偏移的距离attachment.length = 100;//阻尼attachment.damping = 200;//震荡频率attachment.frequency = 50;
2)、iOS9后添加的新方法,什么鬼效果都不知道
//5、拖动item。属性attachmentRange为item距离另一个item达到临界才开始拖动。(锚点、方向向量参数没用???)UIAttachmentBehavior *attachment = [UIAttachmentBehavior slidingAttachmentWithItem:redLabel attachedToItem:cyanView attachmentAnchor:[touches.anyObject locationInView:self] axisOfTranslation:CGVectorMake(0, 1)];//6、拖动item。属性attachmentRange为拖动距离。配合push,只能按固定的方向移动,push方向不对,将不会动(锚点参数没用???)
// UIAttachmentBehavior *attachment = [UIAttachmentBehavior slidingAttachmentWithItem:cyanView attachmentAnchor:[touches.anyObject locationInView:self] axisOfTranslation:CGVectorMake(1, 1)];//7、两个item之间按frame的距离固定在一起,另一个item会被拖着动,不是整体固定。默认锚点为center,可设置偏移offset(有偏移时,会转来转去,且距离会变长)
// UIAttachmentBehavior *attachment = [UIAttachmentBehavior limitAttachmentWithItem:cyanView offsetFromCenter:UIOffsetMake(0, 0) attachedToItem:redLabel offsetFromCenter:UIOffsetMake(0, 0)];//8、两个item之间按frame的距离固定在一起。要动一起旋转动(锚点参数没用???)
// UIAttachmentBehavior *attachment = [UIAttachmentBehavior fixedAttachmentWithItem:cyanView attachedToItem:redLabel attachmentAnchor:[touches.anyObject locationInView:self]];//9、设置一个锚点。item的center到锚点的距离 + 锚点到item2的center距离,等于两个item的固定距离,相互牵引。
// UIAttachmentBehavior *attachment = [UIAttachmentBehavior pinAttachmentWithItem:cyanView attachedToItem:redLabel attachmentAnchor:[touches.anyObject locationInView:self]];//摩擦力矩(???)attachment.frictionTorque = 500;//吸附范围,当两个item超出200的距离时,item就被另一item拖动attachment.attachmentRange = UIFloatRangeMake(-50, 50);
6)、UIDynamicItemBehavior(动力元素行为)
// 动力元素行为UIDynamicItemBehavior * itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[redLabel]];//弹性(0.0-1.0:非弹性-弹性)itemBehavior.elasticity = 1;//摩擦(刚好贴着运动好像没效果,要有一定角度的力,让其贴住其他item或者边界才有摩擦)itemBehavior.friction = 1;//密度(碰撞时,密度高的不怎么动)itemBehavior.density = 1;//阻力系数(阻碍移动,会阻碍重力、也会阻碍反弹)itemBehavior.resistance = 40;//角阻力(阻碍旋转)itemBehavior.angularResistance = 0;//允许旋转itemBehavior.allowsRotation = YES;//线速度(阻力 resistance 依然有效)[itemBehavior addLinearVelocity:CGPointMake(50, 0) forItem:redLabel];//角速度(添加后,允许旋转 allowsRotation = YES,无法修改。角阻力 angularResistance 依然有效)[itemBehavior addAngularVelocity:M_PI_4 forItem:redLabel];
N、粒子动画
0)、写在前面
粒子发射层 继承CALayer,那么阴影、边界、圆角的属性都有。
y轴/x轴速度 小于 加速度(重力) 会有 雪花/风力 效果(cell.velocity < cell.yAcceleration)。
y轴速度 稍大于 加速度(重力) 会有 发射/投掷 效果(cell.velocity > cell.yAcceleration)。
粒子发射层 设为叠加模式会有火焰效果(emitterLayer.renderMode = kCAEmitterLayerAdditive)。
粒子的名字。可以用KVC来设置属性([emitterLayer setValue:[NSNumber numberWithFloat:M_PI] forKey:@"emitterCells.test2.emissionLongitude"];)。
粒子缩放速度。当缩放到0的时候,又会放大,所以想要从birth到lifetime结束都是缩放形式,就需要不断调值,不要缩放太快(cell.scaleSpeed)。
粒子包含粒子。颜色,速度之类的都会叠加,会有意想不到的效果(emitterLayer.emitterCells = @[cell]; cell.emitterCells = @[cell2];)。
粒子的形状emitterShape、模型emitterMode 搞了很久没搞懂。多亏这边文章( http://www.cnblogs.com/densefog/p/5424155.html )
1)、创建粒子发射层
//创建 粒子发射器层layeremitterLayer = [CAEmitterLayer layer];//发射器 frame(可设置合适大小来 masksToBounds )emitterLayer.frame = self.view.bounds;//发射器 发射源起点emitterLayer.emitterPosition = CGPointMake(emitterLayer.frame.size.width / 2.0, emitterLayer.frame.size.height/ 2.0);//发射器 发射源sizeemitterLayer.emitterSize = CGSizeMake(100.0, 100.0);//混合方式(Add是叠加,有火焰效果,其他覆盖)
// kCAEmitterLayerUnordered //无序
// kCAEmitterLayerOldestFirst //老的在(数组)最前面(显示最下层)
// kCAEmitterLayerOldestLast //老的在(数组)最后面(显示最上层)
// kCAEmitterLayerBackToFront //
// kCAEmitterLayerAdditive //叠加emitterLayer.renderMode = kCAEmitterLayerOldestLast;//是否开启超三维空间模式(NO慢慢变白透明消失,YES直接透明消失)emitterLayer.preservesDepth = YES;//发射器形状
// kCAEmitterLayerPoint //发射源一个点,位置来源(emitterPosition)
// kCAEmitterLayerLine //发射源一条线,位置来源(emitterSize,正中的横线)
// kCAEmitterLayerRectangle //发射源一个矩形,位置来源(emitterSize)
// kCAEmitterLayerCuboid //发射源一个立方体,位置来源(emitterSize + emitterZPosition)
// kCAEmitterLayerCircle //发射源一个圆形,位置来源(emitterSize 的内切圆)
// kCAEmitterLayerSphere //发射源一个立体圆形,位置来源(emitterSize + emitterZPosition的内切圆)emitterLayer.emitterShape = kCAEmitterLayerPoint;//发射模型
// kCAEmitterLayerPoints //发射模型一个点
// kCAEmitterLayerOutline //发射模型外框边界
// kCAEmitterLayerSurface //发射模型矩阵里面
// kCAEmitterLayerVolume //emitterLayer.emitterMode = kCAEmitterLayerPoints;//发射Z轴起点emitterLayer.emitterZPosition = 50.0;//发射器的深度emitterLayer.emitterDepth = 50.0;//在一开始生成随机的粒子数?(暂时看不出效果)emitterLayer.seed = 80;//添加到layer层[self.view.layer addSublayer:emitterLayer];
2)、创建粒子
//创建 粒子CAEmitterCell *cell = [[CAEmitterCell alloc] init];//粒子 名称cell.name = @"test";//粒子 图片cell.contents = (__bridge id _Nullable)([UIImage imageNamed:@"2"].CGImage);//粒子 y轴加速度(重力)cell.yAcceleration = 75.f;//-50.f;//粒子 x轴加速度(重力)cell.xAcceleration = 0.f;//粒子 生成速率(/秒,>1.0)cell.birthRate = 1;//粒子 生命周期cell.lifetime = 5.0;//粒子 颜色cell.color = [UIColor colorWithRed:1 green:0.5 blue:0.1 alpha:1.0].CGColor;//粒子 透明速度(-0.0 <-> -1.0,-0.9消失得快,-0.1消失得慢)cell.alphaSpeed = -0.1;//粒子 运动的速度cell.velocity = 50;//粒子 运动的速度范围(velocity +- Range/2 )cell.velocityRange = 50;//粒子旋转角度(0 - Range)cell.spin = 0;//粒子旋转角度范围(0 - Range)cell.spinRange = 0;//粒子 缩放cell.scale = 1;//粒子 缩放速度(-1 <-> 1 ,-变小 +变大,烟花爆炸后效果,如果变小到0又会增大,值需要调试)cell.scaleSpeed = -0.5;//粒子 发射角度cell.emissionLongitude = (M_PI/2)*3;//粒子 发射角度范围(Longitude +- Range/2 )cell.emissionRange = M_PI/2;//颜色变换范围
// cell.greenRange = 1.0;
// cell.redRange = 1.0;
// cell.blueRange = 1.0;//颜色变换速度
// cell.redSpeed =-1.5;
// cell.blueSpeed =+1.5;
// cell.greenSpeed =+1.0;
3)、添加粒子到发射层
//单个粒子动画
emitterLayer.emitterCells = @[cell];//多个粒子同时动画
emitterLayer.emitterCells = @[cell,cell2];//粒子动画包含粒子动画(裂变的感觉)
emitterLayer.emitterCells = @[cell];
cell.emitterCells = @[cell2];
cell2.emitterCells = @[cell3];
注:
在第三种情况,控制好 lifebirthRate 和 lifetime ,可以达到烟花效果。
比如cell是发射效果(这里设为1个/秒吧)、cell3是爆炸效果(几十、几百个/秒),如果,cell3加在cell上,效果就像彗星移动(cell移动的过程中,cell3不断生成)。
那么要实现发射效果,就要加个缓存层cell2。cell的生命周期(N秒) 和cell2的生成率(1个/N秒)一样 ,cell刚消失,cell2才产生。不过因为 lifebirthRate >= 1 。所以目前只有1秒符合。
cell.lifebirthRate = 随意
cell.lifetime = 1.0 + ?;cell2.lifebirthRate = 1.0;
cell2.lifetime = 1.0 + ?;
cell2的图片可以空,等到cell快消失前,生成一个cell2,同时cell2包含的cell3一秒几十、几百个生成,就是发射爆炸效果了。
其他
1、模态视图转场动画
//设置模态视图的转场效果(如X信,朋友的历史单条说说,点击查看详细)。
second.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//推
[self presentViewController:second animated:YES completion:^{
}];
2、自定义转场动画(相当于快照当前屏幕)
// 1、截图UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0);[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();// 2、对截图,添加、置顶UIImageView *coverView = [[UIImageView alloc]initWithFrame:self.view.bounds];coverView.image = coverImage;[self.view addSubview:coverView];// 3、设置好动画后图层// 3-1、比如,淡入淡出,设置好该显示的View,再动画里,让“截图”透明为0。// 3-2、比如,是立方体cube效果,先旋转90度,再在动画里和“截图”一起旋转。// 4、动画[UIView animateWithDuration:1.0 animations:^{// 4-1、对截图进行动画} completion:^(BOOL finished) {// 4-2、完成、移除截图[coverView removeFromSuperview];}];
3、动画所需的变换
3-1、view:CGAffineTransform(缩放、位移、旋转。二维变换)
// 角度 -> 弧度
#define kDEGREES_TO_RADIANS(x) ((x) / 180.0 * M_PI)// 获取正常的
CGAffineTransform t = CGAffineTransformIdentity;// 带make,相对原始的,重复调用同一数据,不会变化
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)// 混合两个make变化
CGAffineTransform t1 = CGAffineTransformMakeScale( 1.5, 1.5);
CGAffineTransform t2 = CGAffineTransformMakeTranslation(50, 50);
CGAffineTransform t = CGAffineTransformConcat(t1, t2);// 在t的基础上,再变化。
// 1、重复调用,可以不断变换。
// 2、可以混合变化,同CGAffineTransformConcat
CGAffineTransform t = self.view.transform;
t = CGAffineTransformRotate(t, kDEGREES_TO_RADIANS(90.0));
t = CGAffineTransformScale(t, 0.5, 0.5);
t = CGAffineTransformTranslate(t, 50, 50);
self.view.transform = t;// 反转,往相反的变换方向变换。
// 1、如果是 Identity 不变换
// 2、缩放0.5 / 左移50 / 旋转90度 ->(相对初始)缩放2.0 / 右移50 / 旋转-90
// 3、所以变化 -> 反转 -> 变化,才能回到最初的状态
CGAffineTransform t = test1.transform;
t = CGAffineTransformInvert(t);
test1.transform = t;// 初始变换函数
// [ a b 0]
// [x y 1] * [ c d 0] = [x' y' 1]
// [ tx ty 1]
//
// x' = ax + cy + tx;
// y' = bx + dy + ty;
//
// CGAffineTransformMake(CGFloat a, CGFloat b,CGFloat c, CGFloat d, CGFloat tx, CGFloat ty);
// 平移
CGAffineTransform t = CGAffineTransformMake(1,0,0,1,tx,ty);
// 缩放
CGAffineTransform t = CGAffineTransformMake(x,0,0,y,0,0);
// 旋转(计算有难度...)
...// 判断是否 原始
CGAffineTransformIsIdentity
// 判断是否 变换相等
CGAffineTransformEqualToTransform
3-2、layer:CATransform3D(缩放、位移、旋转。三维变换)
1)、方法基本同“1-2、CGAffineTransform(缩放、位移、旋转。二维变换)”,不再赘述。
2)、移动、缩放:多了z轴;旋转:绕哪个轴旋转。
3)、最重要的一点,结构体的m34变量,控制透视效果。
m34 = -1.0 / d; //d代表想象中视角和屏幕之间的距离,以像素为单位,大概就可以。通常500-1000。负号是方向。浮点不要漏!
4)、view.layer.sublayerTransform
设置后,所有子layer,围绕view.layer的position(anchorPoint)3D变换。如设置m34属性,有灭点效果。
如单独设置子layer的transform,子layer各自绕自己的position(anchorPoint)3D变换。
5)、想要看起来正常点、像是根据自身的position(anchorPoint),那就设置同样尺寸。
layer.bounds = (CATransformLayer.bounds,有的话) = contentView.bounds。
6)、view.layer.doubleSided 决定是否绘制视图背面,默认YES,转180度,有镜像效果。
7)、用在layer的属性transform,还是扁平化,改变子layer的z轴,无效果,被压缩在父视图上。(搭配CATransformLayer才是真3D)。
8)、假3D立方体效果,参照《iOS:小技巧》 -> “56、用6个view + CATransform3D 构建立方体” 。
9)、真3D立方体效果,参照《iOS:小技巧》 -> “57、用6个layer + CATransform3D + CATransformLayer 构建立方体” 。
4、设置缺省动画(隐式动画)
0)、写在前面
系统检索顺序:1)、- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
1-1)、(Layer)签代理,在需要的地方调用。
1-2)、(View)自定义View.m里重写(因为UIView签了代理,且默认禁掉隐式动画,而各种控件都继承于UIView)
2)、(Layer)self.testLayer.actions
3)、(没试)style字典
4)、(Layer)+ (id<CAAction>)defaultActionForKey:(NSString *)event
禁止隐式动画,除了通过返回nil,也可以在 CATransaction 里实现,参照“2、CATransaction(Layer版的UIView Animation)”
1)、- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
1-1)、直接实现Animation
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{if ([event isEqualToString:@"backgroundColor"]){// 动画1// setBackgroundColor之前,会被系统调用。// 所以,fromValue = layer.backgroundColor。// toValue不填,会自动赋上后来setBackgroundColorCABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];animation.duration = 1.5;animation.fromValue = (__bridge id)layer.backgroundColor;return animation;}return nil;// 返回nil,继续查找action等。// 返回[NSNull null],不再查找。
}
1-2)、自定义Animation
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{if ([event isEqualToString:@"backgroundColor"]){ // 动画2MyAction *action = [[MyAction alloc]initWithOldBackgroundColor:layer.backgroundColor];return action;}return nil;// 返回nil,继续查找action等。// 返回[NSNull null],不再查找。
}
MyAction.h
#import <Foundation/Foundation.h>
#import <QuartzCore/CALayer.h>
#import <QuartzCore/CAAnimation.h>@interface MyAction : NSObject <CAAction>{CGColorRef fromBgColor;
}- (instancetype)initWithOldBackgroundColor:(CGColorRef)oldBgColor;@end
MyAction.m
#import "MyAction.h"
#import <UIKit/UIKit.h>@implementation MyAction// 传动画前的状态
- (instancetype)initWithOldBackgroundColor:(CGColorRef)oldBgColor
{self = [super init];if (self) {fromBgColor = oldBgColor;}return self;
}// 重写
- (void)runActionForKey:(NSString *)event object:(id)anObject arguments:(nullable NSDictionary *)dict
{// setBackgroundColor之后才被系统调用。// 所以,fromValue 需要传值进来。// toValue 填上 setBackgroundColor 后的颜色CALayer *layer = (CALayer*)anObject;CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];animation.duration = 1.5;animation.fromValue = (__bridge id)fromBgColor;animation.toValue = (__bridge id)layer.backgroundColor;[layer addAnimation:animation forKey:@"test"];
}@end
补充:1、两者有所区别:
返回动画,运行时还没被set背景颜色,所以 layer.backgroundColor 获取到之前的。
返回签了CAAction协议的对象,是在set背景颜色之后调用的。
2、如果是立方体、左推等动画转场效果,就不需要考虑是 调用之前、之后 的问题。直接设置就行。
2)、(Layer)self.testLayer.actions
self.testLayer.actions = @{@"backgroundColor":animation/*,@"sublayers":[NSNull null]*/};
如果用 view 的 layer 属性↓,无效果,估计是因为view的隐性动画在“1)、”被禁。
self.testView.layer.actions = @{@"backgroundColor":animation/*,@"sublayers":[NSNull null]*/};
3)、(没试)style字典
4)、(Layer)+ (id<CAAction>)defaultActionForKey:(NSString *)event
+ (id<CAAction>)defaultActionForKey:(NSString *)event
{if ([event isEqualToString:@"backgroundColor"]) {CATransition *animation = [CATransition animation];animation.duration = 1.5;animation.type = @"cube";animation.subtype = kCATransitionFromRight;return animation;}return nil;
}
转载于:https://www.cnblogs.com/leonlincq/p/7412463.html
iOS:动画(18-10-15更)相关推荐
- HTML 18 HTML5 特性 18.10 HTML5 无障碍
HTML 文章目录 HTML 18 HTML5 特性 18.10 HTML5 无障碍 18.10.1 什么是无障碍 What is accessibility? 18.10.2 HTML: 为无障碍提 ...
- 【译】A quick list of new enterprise features in iOS 13, iPadOS, and macOS 10.15 Catalina
苹果WWDC 2019主题演讲就在几个小时前结束,事实证明,正如我们希望的那样,企业有很多新闻,特别是关于身份管理和BYOD的新闻! 现在,这是我们的企业功能初步列表.可能会有更新-我们仍然必须等待完 ...
- 10.15 iptables filter表小案例10.16/10.17/10.18 iptables nat表应用
2019独角兽企业重金招聘Python工程师标准>>> 10.15 iptables filter表小案例 iptables 命令.语法总结 iptables-nvL //查看ipt ...
- 背水一战 Windows 10 (15) - 动画: 缓动动画
背水一战 Windows 10 (15) - 动画: 缓动动画 原文:背水一战 Windows 10 (15) - 动画: 缓动动画 [源码下载] 背水一战 Windows 10 (15) - 动画: ...
- 为 macOS 10.15 开启 HiDPI,让 2K 显示器更舒适
为 macOS 10.15 开启 HiDPI,让 2K 显示器更舒适 stevesun 2019 年 11 月 24 日 Matrix 精选 Matrix 是少数派的写作社区,我们主张分享真实的产品体 ...
- iOS动画-CAAnimation使用详解
理解了隐式动画后,显式动画就更加通俗易懂了.区别于隐式动画的特点,显式动画就是需要我们明确指定类型.时间等参数来实现效果的动画.除此之外,我们也可以创建非线性动画,比如沿着任意一条曲线运动等: 我们平 ...
- iOS动画效果、绘制图形
文章转载自:http://www.cnblogs.com/kenshincui/p/3972100.html 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥 ...
- App适配iPhone 6/ Plus和iOS 8:10条小秘诀
http://www.cocoachina.com/ios/20150108/10864.html (原文:raywenderlich 作者:Jack Wu 译者:@TurtleFromMars) 过 ...
- CALayer与iOS动画 讲解及使用
iOS CALayer与iOS动画 讲解及使用 关于CoreAnimation 初识CALayer CALayer CAAnimation CAMediaTiming UIView与CALayer动画 ...
- iOS动画开发之五——炫酷的粒子效果
iOS动画开发之五--炫酷的粒子效果 在上几篇博客中,我们对UIView层的动画以及iOS的核心动画做了介绍,基本已经可以满足iOS应用项目中所有的动画需求,如果你觉得那些都还不够炫酷,亦或是你灵光一 ...
最新文章
- 民营企业的ERP之路
- OPTEE的内存管理 :页表的创建过程
- VMware workstation运维实践系列博客导航
- oracle数据库第八章答案,Oracle培训(三十)——Oracle 11g 第八章知识点小结——处理数据...
- DGL教程【五】使用自己的数据集
- [html] 在head标签中必不少的是什么?
- java this 三种用法
- 3.7 为什么需要非线性激活函数?
- html5拖放原理,HTML5 拖放实现
- ASP.NET删除等操作前的提示解决方案
- 【web前端开发】vs code插件推荐
- matlab两矩阵乘除,MATLAB矩阵乘法
- 【OMNeT++】ALOHA协议仿真中的channelUtilization
- windows下解决弹窗广告
- 互联网协议 — 802.1q VLAN 虚拟局域网协议
- AD18设计PCB时常见问题及操作
- 客户端设置超时,max_fails失效----问题分析
- DIV+CSS网页设计常用布局代码
- 嵌入式RTOS的 任务栈 和 系统栈
- free -m 详解