[IOS]CoreAnimation基础[翻译2部分]

本文介绍了如何使用CoreAnimation中的图层对象来管理应用程序中的视图内容。内容包括如何选择合适的图层类、如何为图层提供内容、如何调整图层内容以适应不同场景需求等。此外还介绍了如何通过图层样式属性来美化视图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设置图层对象

图层对象是你使用CoreAnimation(以下皆称CA)所进行交互的中心。图层管理你app中的视图内容,并且给这些内容提供可修改的样式和视觉外貌。因为OS X和IOS的不同,要使用CA必须开启该功能,以下一小节将了如何在OS X中开启改效果,所以就略过。



改变一个与视图所关联的图层对象

图层所关联的视图默认创建一个CALayer实例,并且大多数情况下,你并不需要一个不同的图层对象。然而,CA提供了不同的图层类,每一个图层类都提供特定用途。选择某一个不同的图层类可能会提高性能,或者以一种简单的方式来支持某一种视图内容行为。比如CATiledLayer类为展示大图片提供了更高的效率。


改变UIView的Layer Class

你可以重写视图的layerClass方法,以使得该方法返回某一特定的图层类。大多数IOS视图创建CALayer对象,并使用该对象作为后备存储(backing store)。然而对于大多数你自己的视图,这种默认的选择也是很不错的,所以除非必要,不要改变。但是你可能发现某一类型的图层类型更适合在某些情况下。比如,你可能会想要改变图层类型在以下情况的时:

1.你的视图使用到OpenGL 来绘图,这种情况下 你就要用到CAEALLayer对象。

2.某一类的图层类提供了更好的性能。

3.你想要CA图层中的某些特性。比如粒子发光特效。

改变视图的的图层类十分简单,见以下例子2-1。你唯一需要做的就是重写layerClass方法并且将返回的图层类对象改变成你想要返回的。在显示display画面之前,视图会调用layerClass,并且使用返回的视图对象创建新的图层。一旦完成创建,图层就不能再改变了。

+ (Class) layerClass {

   return [CAMetalLayer class];

}

想要了解更多图层类的更多特性见Different Layer Classes Provide Specialized Behaviors.



不同的图层类提供各种特性

CA定义了许多标准图层类,每一个都有特定的使用环境。CALayer是这些图层类的基类。它定义了这些子图层类所必需支持的,并且是视图类所默认使用的。详细见下表2-1

Class 作用

CAEmitterLayer 用来实现基于CA的粒子发光效果,该图层对象控制粒子的产生。

CAGradientLayer用来绘制有色彩梯度的图层

CAMetalLayer 用来建立和。。。这个确实不太明白

CAEAGLLAyer 主要是开发OpenGL所用的图层

CAReplicatorLayer 当你想要自动复制多个子图层的使用

CAScrollLayer 用来管理大片科幻懂的区域并且有多个子图层

CAShapeLayer 用来绘制基于路径的图形的图层

CATextLayer 主要是用来渲染属性字

CATiledLayer 主要用来管理大的图片,该图片可以奋争若干个小的贴瓷,并且支持缩放其中的内容

CATransformLayer 主要用来渲染3D效果




为图层提供内容

图层是管理你app的内容的数据对象。一个图层内容由包含视觉数据的位图组成。你可以以一下三种方式来提供内容。

1.使用图片作为图层的内容,这种方法能为那些静态的或者极少改变的内容提供良好效果

2.使用委托方式(delegate),让委托来绘制图层内容。这种方式对于那些周期改变内容的视图具有很好的效果。

3.直接定义一个图层的子类,然后自己给图层提供内容。如果你想改变基本的图层绘制方式,或者自定义一个图层,那么就使用该种方式。

你在使用这些方式的时候唯一需要担心的在自己创建图层的时候。如果你的app只包含了图层支持的视图,那么你大可放心的使用。图层支持的视图将以最效率的方式为图层提供其内容。


使用图片作为图层的内容

因为图层仅仅是一个管理位图图像的容器,你可以直接将图片传递给图层的contents属性。给图层的属性赋值图片相当简单,并且能够让你准确的指定你想如何呈现图片。图层使用图片对象的时候并不会创建图片的复制copy。这一机制当你在多处使用该图片的时候并不会产生额外的内存开销。

你传递给图层的图片类型必须是CGImageRef类型。记得一定要使用合适分辨率的图片。



使用委托的方式来提供图层内容

如果你的图层内容经常的改变,你可以使用一个委托对象来提供并更新内容。在展现的时候,图层将调用委托的方法来提供必要的内容。

如果你的委托实现了displayLayer方法,那么委托就要负责创建位图并且将位图赋值给图层的contents属性。

如果你的委托实现了drawLayer:inContext方法,CA创建位图,然后讲图像上下位context画进位图。然后调用你的委托方法来填充位图。你的委托方法需要的就是将必要的内容画进去。

委托对象必须实现displayLayer或者drawLayer:inContext两个方法中的任意一个。如果两者都实现了,那只会调用displayLayer方法。

当你的app更倾向于加载或者创建它所想要展示的内容的情况下,重写displayLayer方法将会是最适合的。LIst2-3展示一个例子来实现displayLayer委托方法。在该例中,委托使用了帮助者对象来加载和展示它所需要的内容。委托方法选择哪张图片需要被展示,基于其内部状态。就是例子中displayYesImage属性。


- (void)displayLayer:(CALayer *)theLayer {

    // Check the value of some state property

    if (self.displayYesImage) {

        // Display the Yes image

        theLayer.contents = [someHelperObject loadStateYesImage];

    }

    else {

        // Display the No image

        theLayer.contents = [someHelperObject loadStateNoImage];

    }

}

如果你不想预渲染图片或者预先创建位图,你可以使用drawLayer:inContext方来动态的加载。如2-4所显示的例子。在该方法中委托绘制了一条曲线。

- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext {

    CGMutablePathRef thePath = CGPathCreateMutable();

 

    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);

    CGPathAddCurveToPoint(thePath,

                          NULL,

                          15.f,250.0f,

                          295.0f,250.0f,

                          295.0f,15.0f);

 

    CGContextBeginPath(theContext);

    CGContextAddPath(theContext, thePath);

 

    CGContextSetLineWidth(theContext, 5);

    CGContextStrokePath(theContext);

 

    // Release the path

    CFRelease(thePath);

}


对于定制内容的基于图层的视图,你应重载视图的以上两种方法。基于图层的视图会使自身成为委托,然后实现其两种方法,你并不需要改变其任何配置。作为替代的,你应该重写drawRect方法来绘制你的内容。


通过图层子类提供图层所需的内容

如果你实现了一个定制的图层类,你可以重写你的图层类方法来绘制。通常来说,通过图层来产生内容并不是那么的常见,但是图层确实可以这么做来管理内容。比如,CATiledLayer类管理一个由多块小图所组成的大图片,该图层会分别渲染。只要提供必要的信息,该视图类就会直接绘制其内容。

当使用到子类的时候,你需要遵循以下原则来绘制你的内容:

1.重写图层的display方法,并合理的设置图层属性。

2.重写图层的drawInContext方法,并且在该方法内提供必要的内容

使用以上两种方法决定于你绘制的过程。display方法是你更新图层内容的主入口,所以重写该方法会让你完全的控制绘图过程。重写display方法也意味这你需要创建CGImageRef并赋值给contents属性。如果你仅仅只是想绘制内容,并不想完全的掌控绘图的细节。重写drawInContext方法,图层会为你创建后备存储的。




调整图层内容

当你给你的图层contents属性添加一张图片作为内容时,图层的contentsGravity属性决定了图片时如何适配在当前边界的。默认情况下,图片过大或者过小,图层酒会调整图片成图层的可用大小。如果图层的边界比例与你的图片的比例不一致,这样图片将会失真。所以通过更改contentsGravity属性可以让你的图片适配当前图层。

你可以给contentsGravity属性设置的值可以分为两大类:

1.基于位置的gravity常量能够让你的图片紧贴某一边,或者某一角 而不会调整图片的来适应图层。

2.基于缩放的gravity 常量让你的的图片缩放,保持某一比例或者不保持该比例。

图2-1 展示了基于位置的gravity设置如何影响你的图片。除了kCAGravityCenter常量,其他的常量都会让你的图片紧贴某一边或者某一角。kCAGravityCenter常量,让你的图片居中。这些常量都不会缩放你的图片,所以图片总是以原本的分辨率进行渲染。如果图片大于图层的边界(bounds),那么就进行裁剪。如果图片小于边界,那么如果设置了图层的背景眼,除了图片部分以外的部分将会呈现图层的背景颜色。


2-2展示了基于缩放的gravity 常量如何影响你的图片。这些常量缩放你的图片如果图片并不能准确的显示在图层中。这些常量的区别在于他们如何去处理图片的原来长宽比例。一些常量会保持原有的比例,而一些并不会。默认情况下,图层的contentsGravity属性被设置成 kCAGravityResize,这也是唯一的常量模式并不会保持图片原有比例。






使用高分辨率的图片

图层并不知道如何处理图片的分辨率。图层仅仅只是存储一个指针,指针指向位图,然后尽可能的以最好的方式呈现像素。如果你将一张图片赋值给contents属性,你就必须通过设置contentsScale属性告诉CA关于图像的分辨率改如何调整,该属性的默认值是1,大多数情况下这个值能合理的处理图片分辨率,但是当用到Retina屏上,就需要设置成2.0。

改变contentsScale属性只有当你直接将位图赋值给图层的时候才需要。在UIKit和AppKit中,基于图层的视图会自动的设置该属性以匹配屏幕。




调整图层的视觉样式和外观

图层对象的内置装饰属性如boder边框,backgroundColor背景颜色,这些可以让你来作为图层主要内容的装饰。想知道这些视觉装饰属性如何影响图层的见Layer Style Property Animations.



图层都有自己的背景色和边框

图层可以显示背景色,并且可以添加上边框。背景色在图层图片内容之下渲染,而边框则是出于最顶层。就像图2-3.如果图层包含子图层,那么子图层也在边框之下。因为背景色是在你图片之下的,所以背景色会透过你图片透明的部分。




2-5所示,这些代码设置图层的背景色和边框。这些属性都是可以设置动画效果的。

myLayer.backgroundColor = [NSColor greenColor].CGColor;

myLayer.borderColor = [NSColor blackColor].CGColor;

myLayer.borderWidth = 3.0;


如果你的图层背景色是不透明的,记得将图层的opaque属性设置为YES.这样可以提高性能,比如两两个图层部分相互重叠时。切记如果你的图层边角要设置成圆弧的时候 就不要将其设置为不透明YES。



图层支持圆角

你可以改变边角的弧度半径为你的图层添加圆角边框效果。边角弧度半径是一种将原来的直角遮蔽的装饰效果。如图2-4所示,应为涉及到应用透明遮盖问题,边角弧度半径并不会影响图层中内容,除非设置了maskToBounds=YES.但是边角弧度半径总是会影响图片的背景颜色和边框的样子。



如果要让图层能变成圆角,那么就给cornerRadius属性赋值即可。该属性会应用于四个边角,并且优先展示。




图层内置的阴影

CALayer类包含了多种属性,让你来配置阴影效果。阴影效果通过让你感觉内容就像是浮出底层能增加图层的层次感。阴影效果在你app中合理的使用能够为你的app加分增彩。在图层中,你可以控制阴影的颜色,透明度和形状。

图层阴影的opaque值默认是0,也就是不显示阴影。改变该值,会让CA绘制出阴影。因为阴影默认是由图层来调整位置的,所以,你需要指定阴影的偏移offset来调整阴影的位置。特别需要注意的,该偏移是使用图层的内置坐标系。如图2-5所示





给图层添加自定义属性

CAAnimation和CALayer类通过key—value准则来支持自定义属性。你可以利用该特性来添加或得到值通过自定的key。你甚至可以给某一行为添加自定义的属性,这样当你改变该属性的时候,相应的动画就会执行。

更多信息见Key-Value Coding Compliant Container Classes.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值