iOS核心动画高级技巧笔记(一)

CALayer

  • CALayer用来在屏幕上显示和做动画,UIView仅仅是对CALayer的一个封装,可以通过UIView的高级API间接地使得动画变得很简单

  • UIView没有暴露出来的CALayer的功能:

    • 阴影,圆角,带颜色的边框
    • 3D变换
    • 非矩形范围
    • 透明遮罩
    • 多级非线性动画
  • contents - 我们可以使用CALayer来展示一张图片,而不用UIImageView
    layer.contents = (__bridge id)image.CGImage;
  • contentGravity - 与UIImageViewcontentMode属性一样,contentsGravity的目的是为了决定内容在图层的边界中怎么对齐,contentsGravity可选的常量值有以下一些:

    • kCAGravityCenter
    • kCAGravityTop
    • kCAGravityBottom
    • kCAGravityLeft
    • kCAGravityRight
    • kCAGravityTopLeft
    • kCAGravityTopRight
    • kCAGravityBottomLeft
    • kCAGravityBottomRight
    • kCAGravityResize
    • kCAGravityResizeAspect
    • kCAGravityResizeAspectFill
  • contentsScale - 设置图层的contentsScale属性,适配Retina屏幕
    layer.contentsScale = [UIScreen mainScreen].scale;

  • maskToBoundsUIView(clipsToBounds),CALayer(masksToBounds)决定是否显示超出边界的内容

  • contentsRect - 定义了展示的区域,默认是{0, 0, 1, 1},改为{0,0,0.5,0.5},图片就会被裁剪

    enter image description here

  • contentsCenter - 定义了一个固定的边框和一个在图层上可拉伸的区域,默认是{0, 0, 1, 1}contentsCenter设置为{0.25, 0.25, 0.5, 0.5}的效果:

    enter image description here

  • -drawRect: - 重载该方法,会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以 contentsScale的值。如果没有自定义绘制的任务就不要在子类中写一个空的-drawRect:方法。

    当调用了setNeedsDisplay,会自动调用-drawRect:重绘,重绘时,CALayer会请求它的CALayerDelegate(非正式协议,其实就是说没有CALayerDelegate @protocol可以让你在类里面引用)给他一个寄宿图来显示。它通过调用下面这个方法做到的:

    -(void)displayLayer:(CALayerCALayer *)layer;

    趁着这个机会,如果代理想直接设置contents属性的话,它就可以这么做,不然没有别的方法可以调用了。如果代理不实现-displayLayer:方法,CALayer就会转而尝试调用下面这个方法:

    -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

    CALayer不会自动重绘它的内容,它把重绘的决定权交给了开发者,所以我们需要CALayer重绘时要显式地调用-display

  • 锚点(anchorPoint) - 默认位于图层的中点,所有图层的将会以这个点为中心放置,anchorPoint可以被移动,比如你可以把它置于图层frame的左上角,于是图层的内容将会向右下角的position方向移动,而不是居中了

    enter image description here

    改变了anchorPointposition属性保持固定的值并没有发生改变,但是frame却移动了。


视觉效果

  • 阴影

    • shadowOpacity:设置大于默认值(也就是0)的值,阴影就可以显示,//0.0(不可见) 1.0(完全不透明)

    • shadowColor:控制着阴影的颜色,默认是黑色

    • shadowOffset:控制着阴影的方向和距离,默认值是 {0, -3},宽度控制这阴影横向的位移,高度控制着纵向的位移
    • shadowRadius:控制着阴影的模糊度,当它的值是0的时候,阴影就和视图一样有一个非常确定的边界线。当值越来越大的时候,边界线看上去就会越来越模糊和自然

      shadowRadius设置一个稍大的值

      enter image description here

  • 图层蒙板maskmask本身就是个CALayer类型,有和其他图层一样的绘制和布局属性,mask图层定义了父图层的部分可见区域

    enter image description here

  • 拉伸过滤CALayer有三种拉伸过滤方法,他们是:

    • kCAFilterLinear
    • kCAFilterNearest
    • kCAFilterTrilinear

      • 较小的图或者是差异特别明显、极少斜线的大图,Nearest会保留这种差异明显的特质以呈现更好的结果
      • 对于大多数的图尤其是有很多斜线或曲线轮廓的图片,选用kCAFilterLinear或kCAFilterTrilinear

        如下,默认的kCAFilterLinear选项让我们失望了

        enter image description here

        改变过滤的方法

`view.layer.magnificationFilter = kCAFilterNearest;`

   ![enter image description here](https://zsisme.gitbooks.io/ios-/content/chapter4/4.19.png)
  • 组透明

    • alpha(UIView)opacity(CALayer)都会影响子层级的

      enter image description here

    • 组透明整体实现方案

      • UIViewGroupOpacity -> YES(Info.plist)
      • allowsGroupOpacity(IOS7+可用,相当于UIViewGroupOpacity)
      • shouldRasterize+rasterizationScale(配置屏幕),如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片

变换

  • 仿射变换

    • 混合变换,变换的顺序会影响最终的结果,也就是说旋转之后的平移和平移之后的旋转结果可能不同
  • 3D变换

    • 透视投影(m34),m34的默认值是0,我们可以通过设置m34-1.0 / d来应用透视效果,d代表了想象中视角相机和屏幕之间的距离,通常设置为500~1000
  • 灭点 - 永远位于图层变换之前anchorPoint的位置

  • sublayerTransform - 一次性对包含这些图层的容器做变换

  • doubleSided - 不渲染背面,不影响事件响应,设置hidden或alpha为0会影响事件响应


专用图层

  • CAShapeLayer - 通过矢量图形而不是bitmap来绘制的图层子类

    • 优点

      • 渲染快速(硬件加速)
      • 高效使用内存(不需创建寄宿图)
      • 不会被图层边界剪裁掉(可以在边界之外绘制)
      • 不会出现像素化(矢量图形)
      • 圆角 - 可以单独指定每个角
  • CATextLayer - 使用了Core text,并且渲染得非常快

    • 防止像素化
      textLayer.contentsScale = [UIScreen mainScreen].scale;
  • CATransformLayer - 不能显示它自己的内容。只有当存在了一个能作用域子图层的变换它才真正存在

  • CAGradientLayer - 生成两种或更多颜色平滑渐变,真正好处在于绘制使用了硬件加速

    • 基础渐变
      • startPointendPoint属性,他们决定了渐变的方向
      • colors属性,决定了渐变的颜色
        • 多重渐变
        • locations属性定义了colors属性中每个不同颜色的位置,非强制要求设置,但是如果你给它赋值了就一定要确保locations的数组大小和colors数组大小一定要相同
  • CAReplicatorLayer - 高效生成许多相似的图层

    • 重复图层(Repeating Layers)
      - `instanceCount`属性指定了图层需要重复多少次
      - `instanceTransform`指定了一个`CATransform3D`3D变换
      - 反射 - [ReflectionView](https://github.com/nicklockwood/ReflectionView)
      
  • CAScrollLayer

    • scrollToPoint:方法,它自动适应bounds的原点以便图层内容出现在滑动的地方
    • 内容完全可以超过边界
    • UIScrollView并没有用CAScrollLayer
  • CATiledLayer - 将大图分解成小片然后将他们单独按需载入

    • 小片裁剪,大图裁剪成小图,用CATiledLayer展示
  • CAEmitterLayer - 高性能的粒子引擎,被用来创建实时例子动画如:烟雾,火,雨等等这些效果

    • preservesDepth - 是否将3D例子系统平面化到一个图层(默认值)或者可以在3D空间中混合其他的图层

    • renderMode - 控制着在视觉上粒子图片是如何混合的,kCAEmitterLayerAdditive是叠加效果,其他是覆盖效果

    • CAEmitterCellCAEmitterLayer看上去像是许多CAEmitterCell的容器,这些CAEmitierCell定义了一个粒子效果。你将会为不同的粒子效果定义一个或多个CAEmitterCell作为模版,同时CAEmitterLayer负责基于这些模版实例化一个粒子流。一个CAEmitterCell类似于一个CALayer:它有一个contents属性可以定义为一个CGImage,另外还有一些可设置属性控制着表现和行为。

      • 这种粒子的某一属性的初始值。比如,color属性指定了一个可以混合图片内容颜色的混合色。在示例中,我们将它设置为桔色。
        • 例子某一属性的变化范围。比如emissionRange属性的值是,这意味着例子可以从360度任意位置反射出来。如果指定一个小一些的值,就可以创造出一个圆锥形
        • 指定值在时间线上的变化。比如,在示例中,我们将alphaSpeed设置为-0.4,就是说例子的透明度每过一秒就是减少0.4,这样就有发射出去之后逐渐小时的效果。
  • CAEAGLLayer - 最后的杀手锏,OpenGL

    • 所有东西都是3D空间中有颜色和纹理的三角形
    • GLKit框架
  • AVPlayerLayer

    • AVFoundation框架提供
    • 支持3D,圆角,有色边框,蒙板,阴影等效果