CoreAnimation:
Core Animation自身并不是一个绘图系统。它只是一个负责在硬件上合成和操纵应用内容的基础构件。Core Animation的核心是图层对象,图层对象用于管理和操控你的应用内容。图层将捕获的内容放到一副位图中,图形硬件能够非常容易的操控你的位图。在大部分应用中,图层被作为一种管理视图内容的方式,但是你也可以创建标准的图层,这取决于你自身的需要。
动画类结构:
补充一下,CABasicAnimation还有子类CASpringAnimation,弹簧动画。属性动画贵在属性,CALayer的属性,对应于不同的CALayer,可以针对其属性设置变化,如CAShaperLayer,可以设置strokeEnd属性,做出画笔画图的效果。
隐式动画:
从旧属性值动画到新属性值的动画形式。系统自动补全对象从当前形态到目标形态变化过程的行为。隐式是因为我们并没有指定任何动画的类型。我们仅仅改变了一个属性,然后Core Animation来决定如何并且何时去做动画。例如给某属性赋新值
图层定义和给图层提供内容
图层是管理app内容的数据对象。图层的内容由包含可视数据的位图构成。使用下述三种方式之一可给提供图层的内容:
- 直接赋值一个UIImage对象给图层对象contents属性。(这个技术适用于图层内容从不或几乎不改变的情形。)
- 赋值一个代理给图层,由代理负责绘制图层内容。(该技术适用于图层内容可能偶尔改变,且内容可由外部对象提供,比如视图。)
- 定义一个CALayer的子类并覆盖类的绘图方法,有覆盖的方法返回图层的内容。(该技术适用于你需要创建自定义图层的子类,或者你想改变图层基本的绘图行为。)
图层的种类:
类别 | 用途 |
---|---|
CAShaperLayer | 用于绘制三次贝塞尔曲线。CAShaperLayer对绘制基于路径的形状非常有帮助。因为CAShaperLayer总是生成一个最新的路径。而如果将路径画在图层储备中,一旦图层被缩放,形状就变形了。 |
CATransformLayer | 用于渲染一个真3D的图层层级。而不是由其他图层类实现的2D图层层级。 |
CAEmitterLayer | 用于实现基于Core Animation粒子发射系统。发射器层对象控制粒子的生成和起源 |
CAGradientLayer | 用于绘制一个颜色渐变填充图层的形状(所有圆角矩形边界内的部分) |
CAEAGLLayer/CAOpenGLLayer | 用于设置需要使用OpenGL ES(iOS)或OpenGL(OS X)绘制的内容与内容储备。 |
CAReplicatorLayer | 当你想自动生成一个或多个子层的拷贝。复制器为你生成拷贝并使用你指定的属性值以修改复制品的外观和属性。 |
CAScrollLayer | 用于管理由多个子区域组成的大的可滚动区域 |
CATextLayer | 用于渲染一个无格式或属性文本字符 |
QCCompositionLayer | 用于渲染一个Quartz组件元素(仅在OS X中有效) |
图层和视图相关:
1.图层对象是组织在三维空间的二维平面。它是使用Core Animation执行任何操作的核心构件。和视图一样,图层的可管理信息包括几何结构、内容、可视属性;与视图不同的是,图层没有定义它自己的外观,图层仅管理周围位图的状态信息。
2.基于图层的绘图和基于视图的绘图在技术上有明显的不同。<font color = red>对基于视图的绘图,对视图的改变经常会触发调用视图的drawRect:方法以重绘视图内容。但是此种方式的代价相对较高,因为它是CPU在主线程上的操作。Core Animation通过尽可能的使用图形硬件操纵缓存后的位图来避免了这种开销,从而完成相同或相似的效果。</font>
3.大部分图层<font color = red>不做实际的绘图操作</font>。相反,图层捕获应用的内容并缓存它们到位图中。位图有时也被称为储备(backing store)。当你随后改变了一个图层的属性值,你做的所有工作只是改变了与图层对象相关联的状态信息。当你的更改触发了一个动画,Core Animation会将该图层对应的位图数据和图层的状态信息发送给图形处理硬件。
4.图层不是视图的替代品。因此无法创建一个基于单一图层对象的可视界面。图层是视图的基础设施。具体地,图层让视图的绘图和动画更简单和高效,并且能在绘图和动画时保持高帧率。然而许多事情图层无法做到。图层不能处理事件、绘制内容,特别是在响应链中,或是做一些其他的事情。因此,每个app必须有一个或多个视图来处理这类交互。
自定义图层创建相关
图层创建相关,主要有以下几种方式:
- 直接创建CALayer的子类,重写drawInContext方法
- 创建UIView,在drawRect方法中,通过获取上下文,绘制需要的内容,添加到当前view的Layer上,获取上下文,其实就是获取对应view的Layer
- 创建图层,通过delegate回调方法-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx,动态创建绘制内容。
以上是3种创建自定义图层的方法,补充说明下:
(1)无论采取哪种方法来自定义层,都必须调用CALayer的setNeedsDisplay方法才能正常绘图。
(2)详细现实过程:当UIView需要显示时,它内部的层会准备好一个CGContextRef(图形上下文),然后调用delegate(这里就是UIView)的drawLayer:inContext:方法,并且传入已经准备好的CGContextRef对象。而UIView在drawLayer:inContext:方法中又会调用自己的drawRect:方法。平时在drawRect:中通过UIGraphicsGetCurrentContext()获取的就是由层传入的CGContextRef对象,在drawRect:中完成的所有绘图都会填入层的CGContextRef中,然后被拷贝至屏幕。
注意:不能再将某个UIView设置为CALayer的delegate,因为UIView对象已经是它内部根层的delegate,再次设置为其他层的delegate就会出问题。在设置代理的时候,它并不要求我们遵守协议,说明这个方法是nsobject中的,就不需要再额外的显示遵守协议了。
图层树:
使用Core Animation的app拥有三个图层对象集合。每一个图层对象集合在呈现app内容上都扮演着不同的角色。
<font color = #0099ff>模型图层树</font>中的对象(或简称“图层树”)用的最多。在这个树中的对象是模型对象,模型对象负责存储所有动画的目标值。无论何时改变图层的属性值,你使用的始终是某一个模型对象。
<font color = #0099ff>呈现树</font>中的对象包含所有运行中的动画的瞬时值。图层树对象包含的是动画的目标值,而呈现树中的对象代表显示在屏幕上动画的当前值。你不应该更改这个树中的对象。相反,你使用这些对象来读取当前动画的值,可能用于创建开始于这些值的新的动画。
在<font color = #0099ff>渲染树</font>中的对象执行实际的动画,并且对Core Animation是不公开的。
contentGravity属性:
当给图层的contents属性赋值一个图片,图层的contentsGravity属性确定图片如何适合当前的边界。默认情况下,如果一个图片大于小于当前的边界,图层对象缩放图片以适应有效的空间。如果图层的长宽比和图片的长宽比不一致,这会导致图片被扭曲。所以你可以使用contentsGravity属性来确定你的内容以最佳的方式被呈现。
你可以向contentsGravity属性赋予的值分为两个分类:
1.基于位置的引力约束允许你固定你的图片到图层矩形边界的一个特殊的边缘或角落,不会缩放图片。
2.基于缩放的引力约束允许你伸缩图片使用多个选项之一,某些选项保留长宽比,有些则不保留。
使用高分辨率图片:
图层并不知道当前设备的分辨率信息。图层只是简单的存储一个指向位图的指针,并用给定的有效像素以最佳的方式显示。如果你赋值一个图片给图层的contents属性,你必须给图层的contentsScale属性设置一个正确的值以告诉Core Animation关于图片的分辨率。默认的属性值为1.0,对于在标准分辨率的屏幕上显示图片是正确的。如果你的图片要在Retina屏幕上显示,该值需要设定为2.0。使用[[UIScreen mainScreen] scale]可获取正确的缩放率。
图层的可视样式和外观:
图层对象拥有内建的可视装饰,如边框、背景色。你可以使用这些装饰对图层的主内容进行补充。<font color = red>因为这些可视的装饰不需要任何渲染。</font>装饰让图层在一些情况下让图层成为独立的实体成为可能。你只需设置图层的属性,图层自会处理必要的绘图工作,包括动画。
注意:你可以将图层的背景设置成任何颜色,包括支持透明的颜色或使用模式(pattern)图片。使用模式图片时,渲染是由Core Graphics完成,它使用的是标准坐标系统。标准坐标系统和iOS的坐标系统是不一样的。所以,图片在iOS上得渲染结果是颠倒的。可以使用[backgroundLayer setTransform:CATransform3DMakeScale(1.0, -1.0, 1.0)];解决该问题。
如果你将图层的背景颜色设置为不透明。考虑将图层的opaque属性设置为YES。当合成屏幕上的图层时可以提升系能,图层的后备存储也不需管理alpha通道。如果你给图层设置了非零的圆角半径,则不可以将图层标记为不透明类型。
显式动画的方式呈现图层属性的变化:
CABasicAnimation* fadeAnimation = [CABasicAnimation animationWithKeyPath:@”opacity”;
fadeAnimation.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnimation.toValue = [NSNumber numberWithFloat:0.0];
fadeAnimation.duration = 1.0;
[theLayer addAnimation:fadeAnimation forKey:nil];
//改变图层实际的最后数据值
theLayer.opacity = 0.0; // 记得更新图层树
注意:创建一个显示动画,推荐是赋值一个值给动画对象的fromValue属性。如果你没有为该属性指定值,Core Animation将使用图层的当前值作为开始值。如果已经更新了属性作为它的最终值,这将致使fromValue属性值遭到干扰,结果可能并不是你想要的。
不同于隐式动画,隐式动画会更新图层对象的值。而显示动画不会更改图层树中的数据。<font color = red>显示动画仅是创建了一个动画。在动画结束之后,Core Animation从图层中移除该动画对象并使用当前的数据值重绘图层。</font>如果你想让显示动画的改变成为永久性的,如你在之前的例子中看到的,你必须更新图层属性。
隐式和显示动画都会在当前运行循环周期结束之后开始执行,并且当前的线程必须拥有一个用于执行动画的运行循环runloop。如果你改变了图层的动画属性或者给图层添加了多个动画对象。所有这些动画将会同时被执行。例如将图层移动到屏幕之外的时候添加渐隐动画,这两个动画是同时运行的。然而你可以让动画对象在一个特殊的时间开始执行。
CalculationMode属性:
线性和曲线动画,动画的calculationMode属性被设置为kCAAnimationLinear或CAAnimationCubic,属性值被用于提供定时器信息以生成动画。这些模式值让你最大化控制动画的定时器。
节奏动画,动画的calculationMode属性被设置为kCAAnimationPaced或kCAAnimationCubicPaced,这些属性值不依赖由keyTimes或timingFunctions属性提供的额外定时器值。相反,定时器值被隐式地计算以提供一个常速率动画。
离散动画,动画的calculationMode属性被设置为kCAAnimationDiscrete,该值将引起动画属性从一个关键帧跳到另一个没有任何补间动画的下一个关键帧。计算模式使用keyTimes属性值,但忽略timingFunctions属性。
<font color = red>keyTimes</font>属性为应用在每一关键帧指定应用到每一个关键帧上的计时器。该属性只在calculationMode属性被设置为kCAAnimationLinear,kCAAnimaitonDiscrete,kCAAnimationCubic时被使用。它不使用在节奏动画中。
<font color = red>timingFunctions</font>属性指定使用在每一个关键帧部分的定时曲线(该属性替换了继承的timingFunction属性)。
同时动画多个属性变化:
// Animation 1
CAKeyframeAnimation* widthAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderWidth"];
NSArray* widthValues = [NSArray arrayWithObjects:@1.0, @10.0, @5.0, @30.0, @0.5,@15.0, @2.0, @50.0, @0.0, nil];
widthAnim.values = widthValues;
widthAnim.calculationMode = kCAAnimationPaced;
// Animation 2
CAKeyframeAnimation* colorAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderColor"];
NSArray*colorValues=[NSArray arrayWithObjects:(id)[UIColorgreenColor].CGColor,(id)[UIColorredColor].CGColor,(id)[UIColorblueColor].CGColor, nil];
colorAnim.values = colorValues;
colorAnim.calculationMode = kCAAnimationPaced
// Animation group
CAAnimationGroup* group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil];
group.duration = 5.0;
[myLayer addAnimation:group forKey:@"BorderChanges"];
对于分组动画的更高级的方式是使用一个 <font color = red> 事务对象</font>。事务提供了更加灵活的方式,允许你创建内嵌的动画集合以及给每一个动画赋值不同的动画参数。
检测动画结束:
Core Animaiton提供对动画开始与结束的检测支持。这些通知是执行所有与动画相关的内务处理的最佳时刻。比如说你可能使用开始通知设置一些相关状态信息,使用对应的结束通知清理这些状态。
有两种不同的方式获取关于动画状态的通知:
- 使用setCompletionBlock:方法添加一个完成块给当前的事务。当事务中的所有动画完成后,事务将执行你的完成块。
- 给CAAnimaiton对象赋值一个代理,该代理实现了animationDidStart:方法和animaitonDidStop:finished:代理方法。
如果你想将两个动画链接在一起,使得当第一个动画结束之后启动第二个动画。不要使用动画通知。相反,使用动画对象的beginTime属性在希望的时间启动动画。为了将两个动画链接在一起,设置第二个动画的开始时间为第一个动画的结束时间。
图层、视图和动画
- 原则:如果一个图层属于一个图层支持视图,创建动画的推荐做法是使用由UIKit或AppKit提供的基于视图的动画接口。有几种使用Core Animation接口直接动画图层的方式,但如何创建这些动画依赖于目标平台。
- 视图的动画:UIView类默认是关闭图层动画的,但在动画块中重新启用图层动画。如果想使用Core Animation初始化动画,你必须在一个基于视图的动画块内部执行所有Core Animaiton调用。
[UIView animateWithDuration:1.0 animations:^{
// Change the opacity implicitly.
myView.layer.opacity = 0.0;
// Change the position explicitly.
CABasicAnimation* theAnim=[CABasicAnimation animationWithKeyPath:@"position"];
theAnim.fromValue = [NSValue valueWithCGPoint:myView.layer.position];
theAnim.toValue = [NSValue valueWithCGPoint:myNewPosition];
theAnim.duration = 3.0;
[myView.layer addAnimation:theAnim forKey:@"AnimateFrame"];
}];
约束与动画:如果你使用基于约束的布局规则管理你的视图位置,你必须移除任何可能对动画的配置部分造成干扰的约束。约束将影响所有你对视图的位置和尺寸的改变。也会影响到视图和它的子视图的关系。如果你正在动画改变所有这些项目,你可以移除这些约束后再做改变,接着应用需要的新约束。
图层层级:大多数时候,使用图层的最佳方式是将图层和视图配合使用。可能你需要向视图添加另外的图层对象以增加视图层级。为了获得更佳的性能或者单独使用视图实现你需要的功能会比较困难时而选择使用图层。图层层级在许多方式上都与视图的层级相似。嵌入一个图层到另一个图层中,嵌入的图层(称为sublayer)与父图层(称为superlayer)之间将形成一个父子关系。
图层操作:
行为 | 方法 | 描述 |
---|---|---|
添加图层 | addSublayer: | 给当前的图层添加一个新的子层对象。子层被加入到当前图层的子层列表的末尾。图层将显示在所有与其有相同zPosition属性值的同胞图层的顶部。 |
插入图层 | insertSublayer:above:insertSublayer:atIndex:insertSublay:below: | 将子图层插入到子图层层次中指定的索引或者相对于其他子图层的位置。当插入到其他图层的上方或下方,你仅需指定子图层在子图层数组中的位置。图层的可视性主要由它的zPosition属性决定,然后是由其在子图层数组中的位置决定。 |
移除图层 | removeFromSuperlayer | 将子图层从父图层中移除 |
交换图层 | replaceSublayer:with | 将某个子图层与另外的图层交换位置。如果你插入的图层已经在另外的图层层次中,首先它将从图层之前的图层层次中移除 |
注意:以上方法,不能管理属于layer-backed视图的图层。然而一个layer-backed视图可以作为你创建的独立图层的父图层。
- 子图层的位置和尺寸:当添加和插入一个子图层,在它显示到屏幕之前你必须设置子图层的尺寸和位置。你可以在子图层被添加到图层层次之后更改其位置与尺寸,但应该养成在创建图层的时候就设置这些值的习惯。<font color = red>重要:图层宽和高总是设置整型数</font>。
子图层与剪裁:一个父图层不会自动地裁剪超出其边界的子图层的内容。相反,默认情况下,父图层允许他的子图层完全的被显示。然而,通过设置图层的masksToBounds属性为YES,你可以重新启用裁减功能。
如果圆角半径被指定的话,一个图层的裁减蒙版形状包括图层的圆角半径。下图说明了masksToBounds属性如何影响一个拥有圆角半径的图层。当masksToBounds属性被设置为NO,整个子图层被显示,尽管它已经超出了它的父图层的边界。将masksToBounds属性设为YES,将引起超出父图层的子图层内容被裁减掉。此时使用阴影,则在图片范围内部的阴影会被保留,外部的会被裁剪掉,当图片背景中空透明时明显。合适的做法是在图层下面插入一个等大的图层,用于设置阴影。
过渡动画相关:一个过渡动画对象为图层创建一个可动画的可视过渡。最普遍的过渡对象用法是动画一个图层的显现和消失。与基于属性的动画不同,一个过渡动画操纵一个<font color = red>图层的缓存图片</font>以创建可视效果,如果通过单独的改变属性实现会非常的困难,也许根本无法实现。
myView1和myView2被放置在相同父视图中的相同位置,但只有myView1是当前可视的。推入过渡引起myView1一边渐隐一边向左滑出,直到它被隐藏,而myView2从右侧滑入变成可视。更新两个视图的隐藏属性确保两个视图的可视性在动画的结尾是正确的。对一个图层应用推入过渡,第一个滑出的图层的使用当前的可视性,而右侧滑入的图层使用最后修改后的可视性。
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.duration = 0.5;
// 为两个图层加入过渡动画
[_myView1.layer addAnimation:transition forKey:@"transition"];
[_myView2.layer addAnimation:transition forKey:@"transition"];
// 最后,改变图层的可视性
_myView1.hidden = !_myView1.hidden;
_myView2.hidden = !_myView2.hidden;
当两个图层包含相同的过渡特效,你可以对两个图层应用同一个过渡对象。使用相同的过渡对象也简化了代码。然而,你也可以使用不同的过渡对象并且如果对每个图层过渡参数都是不同的,那么就肯定需要使用两个不同的过渡对象。
fillMode 选项含义:
kCAFillModeForwards:当动画结束后,layer会一直保持着动画最后的状态.
kCAFillModeBackwards:在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始. 你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态。反之,layer会跳一次最终值,然后再开始动画。
both 是上面两者都有,remove则是当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
暂停与恢复动画:为了暂停一个动画,你可以利用图层适配CAMediaTiming协议这一点,设置图层动画的速度为0.0.设置速度为0暂停动画直到你改变该属性值为一个非零值。清单5-4展示了一个简单的关于如何暂停和恢复动画的例子。
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime()
fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime()
fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
显示事务:使用CATransaction类提供的方法创建与管理事务。通过调用begin类方法,可以开始(或隐式地创建)一个新的事务;调用commit类方法可结束一个事务。两个方法之间的代码就是作为事务部分的变化。显示事务可以作用隐式动画。
[CATransaction begin];
theLayer.zPosition = 200.0;
theLayer.opacity = 0.0;
[CATransition commit];
提示动画性能相关:
- 尽可能使用不透明图层:设置opaque属性为YES可以让核心动画知道不需要给图层维持alpha通道,没有alpha通道意味着就不需要渲染这层的背景内容了,从而节省了渲染时间。然后这个属性主要是用于设置层或者以层为基础的视图的,也或者是用于核心动画创造的底层bitmap层的情况。如果把一张图像直接设置为层的contents属性,那么这个图像的alpha通道会被强制保留,无论你设不设定这个值。
- 将复杂路径拆分成简单路径:CAShapeLayer类根据你提供的路径来渲染到bitmap图像,在合成的时候渲染成内容。这么做的优点是层总是在最佳分辨率绘制路径,但是这个优点会消耗额外的渲染时间。如果这个路径太复杂,渲染的代价就会很高,并且如果这个路径的尺寸经常改变(这会导致重绘也经常发生),用于绘画的时间也会增加,这会成为一个阻止最佳表现性能的瓶颈。
- 显式为相同的图层设置contents属性:如果你在多个层对象上使用同一张图片,自己加载图像,把这个图像直接分派给这些层对象的contents属性。分配一个图像到contents属性可以预防分配用于内容储备的内存空间(UIView实际并不将自己绘制到屏幕上,而是先绘制到它的图层上,然后是图层显示在屏幕上,视图并不会频繁的重绘;相反,它的绘图结果会被缓存起来,而绘图的缓存版本(后备存储)将被用到适当的地方)。反而这个层用你提供的图像当做后备存储。当几个层用同样的图片,那么这些层就在共享一份内存而不是为自己再分配一个图片拷贝。
- 总是将图层的尺寸设置为整数值:为了最好的效果,应该将层对象的宽和高设置为整数值,虽然你使用浮点数的形式设定图层边界的宽高,图层的边界最终用于创建一个bitmap图片。指定图层的宽高为整型值会简化Core Animation必要的创建和管理备份存储与其他图层信息的工作。
- 当给图层添加一个阴影指定一个阴影路径:让Core Animation自己决定阴影的形状是个大的开销且影响app的表现。相比让它自己决定,应该用shadowPath属性明确地指定一个阴影形状。当你这么干的时候,核心动画用这个形状去绘制和缓存阴影特效。对那些从不改变或者很少改变形状的层,这是一个很好的效果提升通过减少渲染数量。
视图动画和核心动画一些需要注意的点:
[UIView animate]的方法里只能对UIView的属性进行动画,对于layer的属性是无效的。比如你在这里想让self.AnimateView.layer.cornerRadius = 50.0; 是没有意义的。必须使用CoreAnimation。
选择使用动画样式需要注意:UIView动画优先于CoreAnimation动画
区分不同Anim的方法:1、对于加在一个全局变量上的anima,比如例子里的self.AnimateView ,这是一个全局变量,所以我们在这里可以通过[self.AnimateView.layer animationForKey:]根据动画不同的key来区分2、然而对于一个非全局的变量,比如demo中的progressLayer,可以用KVO:[pathAnimation setValue:@"strokeEndAnimation" forKey:@"animationName"];注意这个animationName是我们自己设定的。
写一个动画比较准确的顺序:先改变model layer的属性,再应用动画。即先赋值给目标对象的属性,然后再添加动画。
UIBezierPath贝塞尔弧线常用方法:
//根据一个矩形画曲线
+ (UIBezierPath *)bezierPathWithRect:(CGRect)rect
//根据矩形框的内切圆画曲线
+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect
//根据矩形画带圆角的曲线
+ (UIBezierPath *)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius
//在矩形中,可以针对四角中的某个角加圆角
+ (UIBezierPath *)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii
参数:
corners:枚举值,可以选择某个角
cornerRadii:圆角的大小
//以某个中心点画弧线
+ (UIBezierPath *)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
参数:
center:弧线中心点的坐标
radius:弧线所在圆的半径
startAngle:弧线开始的角度值
endAngle:弧线结束的角度值
clockwise:是否顺时针画弧线
//画二元曲线,一般和moveToPoint配合使用
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint
参数:
endPoint:曲线的终点
controlPoint:画曲线的基准点
//以三个点画一段曲线,一般和moveToPoint配合使用
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
参数:
endPoint:曲线的终点
controlPoint1:画曲线的第一个基准点
controlPoint2:画曲线的第二个基准点
推荐:网站1