ios动画相关技术

   日期:2020-07-02     浏览:96    评论:0    
核心提示:绚丽动画效果是IOS系统的一大特点,通过UIView层封装的动画,基本可以满足应用开发的大部分需求,但如果想要满足自由的控制动画的展示,就需要使用CoreAnimation框架中的一些类和方法!下图就很好的展示了![在这里插入图片描述](https://img-blog.csdnimg.cn/20200629192456349.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9

一,iOS动画概念

      绚丽动画效果是IOS系统的一大特点,通过UIView层封装的动画,基本可以满足应用开发的大部分需求,但如果想要满足自由的控制动画的展示,就需要使用CoreAnimation框架中的一些类和方法!下图就很好的展示了UIKit与CoreAnimation的关系!如下图:

1, Layer和view的关系与区别

      UIView通过内部图层layer显示在屏幕上,本身并不能显示。当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的layer图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示,如图:

Layer是专门用来辅助我们绘制图像的层,通过每个坐标点与矩阵的运算,来决定最后绘制的状态!而view是要用来接受事件和处理用户交互的。然而,每一个view中,都有一个layer属性来辅助我们进行图形的绘制,并且Layer是可以层级嵌套的。

2, view的2D形变

UIView有个transform的属性,通过设置该属性,我们可以实现调整该view在其superView中的大小和位置,具体来说,Transform(变化矩阵)是一种3×3的矩阵,通过这个矩阵我们可以对一个坐标系统进行缩放,平移,旋转以及这两者的任意组着操作。而且矩阵的操作不具备交换律,即矩阵的操作的顺序不同会导致不同的结果。

struct CGAffineTransform {
  CGFloat a, b, c, d;
  CGFloat tx, ty;
};



//原本默认的设置
self.containerView.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
//添加简单的动画
  [UIView animateWithDuration:1.0f animations:^{
    self.containerView.transform = CGAffineTransformMakeRotation(-30);
  }];

系统已经给出了方便的api调用

//平移
CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)
//缩放
CGAffineTransformMakeScale(CGFloat sx,CGFloat sy)
//旋转
CGAffineTransformMakeRotation(CGFloat angle) (angle 旋转的角度)
//恢复
CGAffineTransformInvert(CGAffineTransform t)

案例:user1

3, layer的3D形变

      CALayer同样也有一个transform属性,但它的类型是CATransform3D,而不是CGAffineTransform。CALayer对应于UIView的transform属性叫做affineTransform.CATransform3D也是一个矩阵,但是和2x3的矩阵不同,CATransform3D是一个可以在3维空间内做变换的4x4的矩阵. ,如图

struct CATransform3D
{
CGFloatm11(x缩放),m12(y切变),m13(旋转),m14();
 
CGFloatm21(x切变),m22(y缩放),m23(),m24();
 
CGFloatm31(旋转),m32( ),m33(),m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);
 
CGFloatm41(x平移),m42(y平移),m43(z平移),m44();
};

4, 正投影与透视投影


m34:管理z方向的深度,m34 = -1/z中,当z为正的时候,是我们人眼观察现实世界的效果,即在投影平面上表现出近大远小的效果,z越靠近原点则这种效果越明显,越远离原点则越来越不明显,当z为正无穷大的时候,则失去了近大远小的效果,此时投影线垂直于投影平面!
案例:user2

绕任意一个轴旋转公式:
)

CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) 
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

二, 图层及其相关子类

案例讲解:

1,显示动画与隐式动画

CATransaction:
CATransaction是事务,用于批量提交多个对layer-tree的操作,并且是原子性的。所有对layer-tree的修改都必须包含在事务内。事务可以嵌套。

隐式CATransaction:
所有对layer-tree的操作都必须处于事务。修改UIView的属性最终也是修改到了layer-tree。当我们改动到layer-tree时,如果当前没有显式创建过CATransaction,则系统会创建一个隐式的CATransaction,这个隐式CATransaction会在RunLoop结束后commit。
另外事务可以嵌套,当事务嵌套时候,只有最外层的事务commit了之后,整个动画才会执行。

案例CATransaction

2,锚点

锚点:锚点决定了图层的绘制位置以及在动画被展示时其参照的点,瞄点的取值范围为0~1(Layer层的position参照点始终和和锚点重合)(决定了旋转,放大,缩小的参照点)(anchorPoint设置锚点)如图:

案例anchorPoint

3,CAEmitterLayer

用于控制粒子效果,例如,钱包雨,烟花,火焰等效果
案例:FFEmitterDemo

4,CTransformLayer

用于渲染3D Layer 层次结构,就像在其子view上可以实现layer任意的旋转
案例:user3

5,CAGradientLayer

用于控制颜色渐变,项目里经常用到
案例:CAGradient

三,核心动画

      在CoreAnimation中,动画效果都是添加在图层的变化上的,通过CALayer,我们组织复杂的层级结构。例如:改变图层的大小,颜色,圆角等。layer层并不决定试图的展示,它只是存储了试图的几何状态。

1,转场动画(CATransition)

CATransition类实现层的转场动画。你可以从一组预定义的转换或者通过提供定制的CIFilter实例来指定转场效果。
案例:CATransition
例子:

UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
        
    UIView *yellowView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    yellowView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:yellowView];
    
    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button2 setTitle:@"改变2" forState:UIControlStateNormal];
    button2.frame = CGRectMake(10, 500, 300, 40);
    [button2 addTarget:self action:@selector(changeUIView2) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button2];
- (void)changeUIView2
{
   CATransition *transition = [CATransition animation];
   transition.delegate = self;
   transition.duration = 1.5f;
   transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
   //@"cube" @"moveIn" @"reveal" @"fade"(default) @"pageCurl" @"pageUnCurl" @"suckEffect" @"rippleEffect" @"oglFlip"
   transition.type = @"rippleEffect";//另一种设置动画效果方法
   transition.subtype = kCATransitionFromLeft;
   [self.view exchangeSubviewAtIndex:1 withSubviewAtIndex:0];
   [self.view.layer addAnimation:transition forKey:@"animation"];
}

2,CABasicAnimation && CAAnimationGroup

CABasicAnimation 为layer属性提供了基础的帧动画能力。
CAAnimationGroup是可以保存一组动画对象,将 CAAnimationGroup对象加入图层后,组中所有动画对象可以同时并发运行。
案例:CABasicAnimation

CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.fromValue = @(self.containerView.center.y);
positionAnima.toValue = @(self.containerView.center.y-100);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
transformAnima.fromValue = @(0);
transformAnima.toValue = @(3 * M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

CAAnimationGroup *animaGroup = [CAAnimationGroup animation];
animaGroup.duration = 4;
animaGroup.fillMode = kCAFillModeForwards;
///为了让呈现树的图形不移除
animaGroup.removedOnCompletion = NO;

animaGroup.fillMode = kCAFillModeForwards;
animaGroup.repeatCount = 1;
animaGroup.animations = @[positionAnima,transformAnima];

[self.containerView.layer addAnimation:animaGroup forKey:@"Animation"];

3,CASpringAnimation

iOS 9 新出的CASpringAnimation,是苹果专门解决开发者关于弹簧动画的这个需求而封装的类。
案例:CASpringAnimation

- (void)springAnimationTextAction:(CGPoint)point {
  CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:@"bounds"];
  //路径计算模式 (@"position")
  if ([springAnimation.keyPath isEqualToString:@"position"]) {
      springAnimation.fromValue = [NSValue valueWithCGPoint:self.containerView.layer.position];
      springAnimation.toValue = [NSValue valueWithCGPoint:point];
  }else if ([springAnimation.keyPath isEqualToString:@"position.x"]) {  
      springAnimation.fromValue = @(self.containerView.layer.position.x);
      springAnimation.toValue = @(point.x);
  }else if ([springAnimation.keyPath isEqualToString:@"position.y"]) {
      springAnimation.fromValue = @(self.containerView.layer.position.y);
      springAnimation.toValue = @(point.y);
  }else if ([springAnimation.keyPath isEqualToString:@"bounds"]) {
      springAnimation.fromValue = [NSValue valueWithCGRect:CGRectMake(point.x, point.y, 500, 500)];
      springAnimation.toValue = [NSValue valueWithCGRect:self.containerView.frame];
  }  
  //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 Defaults to one
  springAnimation.mass = 5;
  //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 Defaults to 100
  springAnimation.stiffness = 100;
  //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 Defaults to 10
  springAnimation.damping = 3;
  //初始速率,动画视图的初始速度大小 Defaults to zero
  //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反
  springAnimation.initialVelocity = 10;
  //估算时间 返回弹簧动画到停止时的估算时间,根据当前的动画参数估算
  NSLog(@"====%f",springAnimation.settlingDuration);
  springAnimation.duration = springAnimation.settlingDuration;
  //removedOnCompletion 默认为YES 为YES时,动画结束后,恢复到原来状态
  springAnimation.removedOnCompletion = NO;
  [self.containerView.layer addAnimation:springAnimation forKey:@"springAnimation"];
}

4,CAKeyFrameAnimation

任何动画要表现运动或变化,至少前后要给出两个不同的关键状态,而中间状态的变化和衔接电脑可以自动完成,在Flash中,表示关键状态的帧动画叫做关键帧动画
案例:CAKeyFrameAnimation

   CALayer *layer = [CALayer layer];
   layer.bounds = CGRectMake(0, 0, 120, 120);
   //与基础动画不同,关键帧动画必须指明动画初始值
   layer.position = CGPointMake(100, 300);
   layer.cornerRadius = 60;
   layer.masksToBounds = YES;
   layer.contents = (id)[UIImage imageNamed:@"timg"].CGImage;
   [self.view.layer addSublayer:layer];
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    CALayer *layer = [self.view.layer.sublayers lastObject];
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    //设置关键帧
    //与基础动画不同,关键帧动画必须指明动画初始值
    NSValue *value1 = [NSValue valueWithCGPoint:layer.position];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(50, 300)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(50, 100)];
    animation.duration = 2;
    animation.values = @[value1,value2,value3];
    animation.autoreverses = YES;
    [layer addAnimation:animation forKey:nil];
}

四,参考:

1,https://www.jianshu.com/p/469a406db8a3
2,https://www.jianshu.com/p/941fc7105c7a
3,https://blog.csdn.net/ssirreplaceable/article/details/52979399
4,https://www.cnblogs.com/LifeTechnologySupporter/p/10353073.html

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服