UIView layer 的对应关系
2016-06-15 09:55
671 查看
一、添加Quartz Core
框架
要使用 Quartz Core
框架,你需要将其添加到你的工程中。然后 #import <Quartz Core/QuartzCore.h>
二、认识图层
对 ps
有所了解的人都知道图层的概念,在这里也一样。在PS中一张图片至少得有一个图层,一个或多个图层的叠加构成了一张位图。我们这里一个或多个图层的叠加的构成了UIView(或其派生类)对象。看过我关于
UIView 文章的人可能会有疑问:UIView
和图层没啥区别啊?NO,还是有区别的,图层是有弹性的,你可以操纵图层,使 UIView
有各种效果,比如三维效果,形变等等。
要访问一个图层,需要读取 UIview
的 layer 属性。
[java] viewplaincopy
1 CALayer* layer = self.view.layer;
所有派生自UIView
的对象,都会继承这一属性,这意味着你可以对导航栏、表格、文本框以及其他许多类型的视图类,进行变换、缩放、旋转、甚至加入动画。
有人又有疑问了,上面的代码我们只读取了一个 layer
假如一个UIView
有多个图层呢?
不错UIView确实只有一个layer
属性,但是layer
是可以叠加的,layer
可以叠加在 layer
上面,所以这个layer
就相当于是一块底板,我们可以在这块地板上叠加一些透明胶片(子图层),叠加在一起之后就构成了一个组合图像。
三、图层的层次结构
图层有很多通用的方法和属性,来操作子图层和执行绘制操作。这些方法允许你将许多单个图层叠加在一起,来绘制一个组合的屏幕图像。
一个图层可以有许多个子图层。在最终绘制屏幕时,子图层可以被排列后固定在一起。这可以参考赛车游戏中的图层。游戏可能有几个图层组成:一个绘制背景、一个绘制角色、一个绘制地图显示器。你可能会为每个图层准备一个专门的UIView类,并另外用一个UIView类来整合游戏画面:
[java] viewplaincopy
1 UIView* gameView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame] ];
2 UIView* backgroundView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame]];
3 UIView* roleView= [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, 100.0, 200.0)];
4 UIView* mapView = [[UIView alloc]initWithFrame:CGRectMake(200.0, 0.0, 100.0, 100.0)];
5 //通过CALayer 类的addSublayer 方法,你可以将3个UIView 类的图层全都与 gameView 对象链接在一起:
6 CALayer* gameLayer = gameView.layer;
7 [gameLayer addSublayer:backgroundView.layer];
8 [gameLayer addSublayer:roleView.layer];
9 [gameLayer addSublayer:mapView.layer];
当gameView
对象显示在屏幕上的时候,3个子图层被合并在一起绘制出来。每个类单独绘制他自己的图层,但当游戏图层被显示出来的时候,3个图层就全都融合在一起了。
gameView不是唯一能够添加子图层的图层。子图层也可以添加自己的子图层,并且可以构建一个完整的图层层次结构。例如你的游戏可能会在 mapView图层中再构加入一个图层,用来显示map的一部分内容,比如剩余里程数。
[java] viewplaincopy
1 UILabel* lastDistance = [[UILabel alloc]initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)];
2 [mapView.layer addSublayer:lastDistance.layer];
此外,通过设置图层的position属性,你还可以不用改变图层的大小就对其位置进行调整。这个属性接受一个CGPoint
结构体,来定位图层在屏幕上的偏移位置。与frame
属性不同,position
属性指定的是图层的重点,而不是左上角:
[java] viewplaincopy
1 CGPoint lastDistancePosition = CGPointMake(100.0, 100.0);
2 lastDistance.layer.position = lastDistancePosition;
四、布局与显示
除了添加子图层之外,CALayer
类还提供了很多不同的方法,可以来插入、调整和移除子图层。
当你用addSublayer
来添加一个子图层时,他会被添加到图层层次结构的顶层,所以他会显示在现有所有子图层的最前面。用一组名为insertSublayer的替代方法,你可以将新视图插入现有的图层之间。
用atIndex
参数,可以将一个图层插入到指定的下标位置:
[java] viewplaincopy
1 [gamelayer insertSublayer:mapView.layer atIndex:1];
要将一个图层插入到另一个图层的上面或者下面,可以加上 above
或 below 参数:
[java] viewplaincopy
1 [ gamelayer insertSublayer:mapView.layer below:backgroundView.layer];
2 [ gamelayer insertSublayer:mapView.layer above:roleView.layer];
调用子图层的 removeFromSuperlayer
方法,可以将图层从他的父图层中删除:
[java] viewplaincopy
1 [ mapView.layer removeFromSuperlayer];
要用另外一个图层代替现有的一个子图层,可以用replaceSublayer方法:
[java] viewplaincopy
1 [ gamelayer replaceSublayer:backgroundView.layer with:newBackgroundView.layer ];
要将子图层保留在图层栈中,但是又想让他在显示的时候不可见,可以设置图层的
hidden 属性。你可以用下面的代码来切换map
显示,而不必真的把图层去掉:
[java] viewplaincopy
1 - (void) Togglemap{
2 mapView.layer.hidden = (mapView.layer.hidden == NO)?YES:NO;
3 }
五、绘制
在更新一个图层时,变化不是立刻被绘制在屏幕上的。这样你就可以偷偷地对图层做很多写操作而不会被展示给用户,直到所有的操作全部结束为止。当图层准备好可以进行重画时,就调用图层的
setNeedsDisplay 方法:
[java] viewplaincopy
1 [ gamelayer setNeedsDisplsy ];
有些时候,可能仅仅不要重画整个图层的部分内容。重新绘制整个屏幕会令程序性能低下。用 setNeedsDisplayInRect
方法,可以只重画需要更新的部分屏幕,这个方法需要一个表示更新区域的CGRect
结构体作为参数:
[java] viewplaincopy
1 CGRect mapViewFrame =CGRectMake(150.0,150,75.0,75.0);
2 [ gameLayer setNeedsDisplayInRect:mapViewFrame ];
如果你在使用Core Graphics
框架进行绘制,可以直接在一个 Core Graphics
上下文中绘制。使用renderInContext
方法可以做到这一点:
[java] viewplaincopy
1 CGContextRef myCGContext = UIGraphicsGetCurrentContext();
2 [ gamelayer renderInContext:myCGContext ];
六、变换
要为图层加上一个三维变换或者仿射变换,可以分别设置图层的 transform
或 affineTransform
属性。
[java] viewplaincopy
1 roleview.layer.transform = CATransform3DMakeScale( -1.0,-1.0,1.0);
2 CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);
3 backgroundView.layer.affineTransform =transform ;
七、图层动画
QuartzCore 的能力远远不止一个简单的画板式图层。他可以将一个二维物体变换为一个令人瞠目结舌的三维纹理,用于创建NB的转场动画。
我之前写过一篇介绍转场动画的文章,那是一种在不同 UIView
对象之间进行过度的手段。你可以直接将转场动画用于图层或子图层。动画可以作为 CAtransition
对象创建出来。
图层转场增强了现有的 CATransition
类,为其提供了一种方法,能用Quartz Core
的动画引擎来添加动画。这令开发者可以利用Quartz Core提供的三维功能,而不必对代码做大的改动。当图层被动画使,一个 CATransition
或CAAnimation
对象会被附加在图层上。然后图层会调用Quartz Core,分支出一个新线程,负责动画的全部图形处理工作。开发者秩序加入期望的动画,就可以提升一个现有图层的功能。用下面的例子代码,可以创建一个转场:
[java] viewplaincopy
1 CATransition* animation = [[CATransition alloc]init];
2 animation.duration =1.0;
3 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
4 animation.type = kCATransitionPush;
5 animation.subtype = kCATransitionFromRight;
警告:到目前为止,恶心的的苹果允许用户创建的转场类型仍然极其有限。Quartz Core
框架内部还支持相当多的其他转场效果,例如自然翻页和缩放转场等,但是受到限制,只能有苹果自己的应用程序使用。(恶心吧)
通过创建一个CABasicAnimation
对象,你就可以创建出一个动画。下面的例子创建了一个动画,将图层旋转了整整360度:
[java] viewplaincopy
1 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
2 animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.1415, 0, 0, 1.0)];
3 animation.duration =3.0;
4 animation.cumulative =YES;
5 animation.repeatCount=2;
创建好之后,你可以直接将动画或者转场应用到一个图层上:
[java] viewplaincopy
1 [mapView.layer addAnimation:animation forKey:@"animation"];
八、图层变换
QuartzCore 的渲染能力可以像三维一样对二维图像进行任意操纵。一个图像可以在x-y-z
三维轴上进行任意角度旋转、缩放和扭曲。CATransform3D
函数族是苹果的Cover Flow
技术以及 iPhone
上使用的其他美观特效的幕后力量。iPhone
支持包括缩放、旋转、仿射、平移等。
变换实在单独的图层上执行的,因此多个变换可以在一个图层表面上同时进行。Quartz Core
框架用 CATransform3D
对象来执行变换。这个对象作用于视图的图层,根据期望的三维设置对图层进行弯折或者其他操作。
应用程序可以仍然将对象看作是二维的,但是当对象呈现给用户时,会遵从已经作用于图层之上的任何变换。下面的例子创建了一个变换,目的是对一个图层进行旋转:
[java] viewplaincopy
1 CATransform3D myTransform;
2 myTransform = CATransform3DMakeRotation(angle,x,y,z);
CATransform3DMakeRotation 函数创建了一个变换,对一个图形进行旋转,旋转角度angle
单位为弧度,轴为 x-y-z
。x-y-z
的值定义了轴上在各个方向上的度量(介于-1和+1之间)。在一个轴上赋予值,就会指示变换绕该轴进行旋转。可以把这些值看作是插在图像上的草棍。如果草棍是沿着
x 轴插进去的,那么图像将绕着草棍垂直旋转。你可以使用不同角度值作为轴,产生出更复杂的转动。不过对于大多数用途来说,用-1
和 +1
这两个值就够了。
要将一个图层绕水平轴转动(垂直转动)45度,可以使用下面的代码:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation(0.78,1.0,0.0,0.0);//0.78 是角度45度换成弧度得到的
要在水平方向上转动同样的角度,可以换成 y
轴指定一个值:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation(0.78,0.0,1.0,0.0);
你可以自己编写一个角度转弧度的函数:
[java] viewplaincopy
1 double radians(float degrees){
2 return (degrees*3.14159265)/180.0;
3 }
当你创建的时候就调用这个函数:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation( radians(45.0),0.0,1.0,0.0);
变换创建完毕之后,就要作用于你要操纵的图层了。CALayer
对象提供了一个 transform属性,可以用来将变换附加到图层之上。图层将会执行任何赋予这个属性的变换:
[java] viewplaincopy
1 roleView.layer.transform = myTransform;
当这个对象被显示出来时,会按照应用在他上面的变换进行显示。在你的代码里,还是会将这个对象作为一个二维物体来引用,但是他会根据变换来进行渲染。
框架
要使用 Quartz Core
框架,你需要将其添加到你的工程中。然后 #import <Quartz Core/QuartzCore.h>
二、认识图层
对 ps
有所了解的人都知道图层的概念,在这里也一样。在PS中一张图片至少得有一个图层,一个或多个图层的叠加构成了一张位图。我们这里一个或多个图层的叠加的构成了UIView(或其派生类)对象。看过我关于
UIView 文章的人可能会有疑问:UIView
和图层没啥区别啊?NO,还是有区别的,图层是有弹性的,你可以操纵图层,使 UIView
有各种效果,比如三维效果,形变等等。
要访问一个图层,需要读取 UIview
的 layer 属性。
[java] viewplaincopy
1 CALayer* layer = self.view.layer;
所有派生自UIView
的对象,都会继承这一属性,这意味着你可以对导航栏、表格、文本框以及其他许多类型的视图类,进行变换、缩放、旋转、甚至加入动画。
有人又有疑问了,上面的代码我们只读取了一个 layer
假如一个UIView
有多个图层呢?
不错UIView确实只有一个layer
属性,但是layer
是可以叠加的,layer
可以叠加在 layer
上面,所以这个layer
就相当于是一块底板,我们可以在这块地板上叠加一些透明胶片(子图层),叠加在一起之后就构成了一个组合图像。
三、图层的层次结构
图层有很多通用的方法和属性,来操作子图层和执行绘制操作。这些方法允许你将许多单个图层叠加在一起,来绘制一个组合的屏幕图像。
一个图层可以有许多个子图层。在最终绘制屏幕时,子图层可以被排列后固定在一起。这可以参考赛车游戏中的图层。游戏可能有几个图层组成:一个绘制背景、一个绘制角色、一个绘制地图显示器。你可能会为每个图层准备一个专门的UIView类,并另外用一个UIView类来整合游戏画面:
[java] viewplaincopy
1 UIView* gameView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame] ];
2 UIView* backgroundView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]applicationFrame]];
3 UIView* roleView= [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, 100.0, 200.0)];
4 UIView* mapView = [[UIView alloc]initWithFrame:CGRectMake(200.0, 0.0, 100.0, 100.0)];
5 //通过CALayer 类的addSublayer 方法,你可以将3个UIView 类的图层全都与 gameView 对象链接在一起:
6 CALayer* gameLayer = gameView.layer;
7 [gameLayer addSublayer:backgroundView.layer];
8 [gameLayer addSublayer:roleView.layer];
9 [gameLayer addSublayer:mapView.layer];
当gameView
对象显示在屏幕上的时候,3个子图层被合并在一起绘制出来。每个类单独绘制他自己的图层,但当游戏图层被显示出来的时候,3个图层就全都融合在一起了。
gameView不是唯一能够添加子图层的图层。子图层也可以添加自己的子图层,并且可以构建一个完整的图层层次结构。例如你的游戏可能会在 mapView图层中再构加入一个图层,用来显示map的一部分内容,比如剩余里程数。
[java] viewplaincopy
1 UILabel* lastDistance = [[UILabel alloc]initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)];
2 [mapView.layer addSublayer:lastDistance.layer];
此外,通过设置图层的position属性,你还可以不用改变图层的大小就对其位置进行调整。这个属性接受一个CGPoint
结构体,来定位图层在屏幕上的偏移位置。与frame
属性不同,position
属性指定的是图层的重点,而不是左上角:
[java] viewplaincopy
1 CGPoint lastDistancePosition = CGPointMake(100.0, 100.0);
2 lastDistance.layer.position = lastDistancePosition;
四、布局与显示
除了添加子图层之外,CALayer
类还提供了很多不同的方法,可以来插入、调整和移除子图层。
当你用addSublayer
来添加一个子图层时,他会被添加到图层层次结构的顶层,所以他会显示在现有所有子图层的最前面。用一组名为insertSublayer的替代方法,你可以将新视图插入现有的图层之间。
用atIndex
参数,可以将一个图层插入到指定的下标位置:
[java] viewplaincopy
1 [gamelayer insertSublayer:mapView.layer atIndex:1];
要将一个图层插入到另一个图层的上面或者下面,可以加上 above
或 below 参数:
[java] viewplaincopy
1 [ gamelayer insertSublayer:mapView.layer below:backgroundView.layer];
2 [ gamelayer insertSublayer:mapView.layer above:roleView.layer];
调用子图层的 removeFromSuperlayer
方法,可以将图层从他的父图层中删除:
[java] viewplaincopy
1 [ mapView.layer removeFromSuperlayer];
要用另外一个图层代替现有的一个子图层,可以用replaceSublayer方法:
[java] viewplaincopy
1 [ gamelayer replaceSublayer:backgroundView.layer with:newBackgroundView.layer ];
要将子图层保留在图层栈中,但是又想让他在显示的时候不可见,可以设置图层的
hidden 属性。你可以用下面的代码来切换map
显示,而不必真的把图层去掉:
[java] viewplaincopy
1 - (void) Togglemap{
2 mapView.layer.hidden = (mapView.layer.hidden == NO)?YES:NO;
3 }
五、绘制
在更新一个图层时,变化不是立刻被绘制在屏幕上的。这样你就可以偷偷地对图层做很多写操作而不会被展示给用户,直到所有的操作全部结束为止。当图层准备好可以进行重画时,就调用图层的
setNeedsDisplay 方法:
[java] viewplaincopy
1 [ gamelayer setNeedsDisplsy ];
有些时候,可能仅仅不要重画整个图层的部分内容。重新绘制整个屏幕会令程序性能低下。用 setNeedsDisplayInRect
方法,可以只重画需要更新的部分屏幕,这个方法需要一个表示更新区域的CGRect
结构体作为参数:
[java] viewplaincopy
1 CGRect mapViewFrame =CGRectMake(150.0,150,75.0,75.0);
2 [ gameLayer setNeedsDisplayInRect:mapViewFrame ];
如果你在使用Core Graphics
框架进行绘制,可以直接在一个 Core Graphics
上下文中绘制。使用renderInContext
方法可以做到这一点:
[java] viewplaincopy
1 CGContextRef myCGContext = UIGraphicsGetCurrentContext();
2 [ gamelayer renderInContext:myCGContext ];
六、变换
要为图层加上一个三维变换或者仿射变换,可以分别设置图层的 transform
或 affineTransform
属性。
[java] viewplaincopy
1 roleview.layer.transform = CATransform3DMakeScale( -1.0,-1.0,1.0);
2 CGAffineTransform transform = CGAffineTransformMakeRotation(45.0);
3 backgroundView.layer.affineTransform =transform ;
七、图层动画
QuartzCore 的能力远远不止一个简单的画板式图层。他可以将一个二维物体变换为一个令人瞠目结舌的三维纹理,用于创建NB的转场动画。
我之前写过一篇介绍转场动画的文章,那是一种在不同 UIView
对象之间进行过度的手段。你可以直接将转场动画用于图层或子图层。动画可以作为 CAtransition
对象创建出来。
图层转场增强了现有的 CATransition
类,为其提供了一种方法,能用Quartz Core
的动画引擎来添加动画。这令开发者可以利用Quartz Core提供的三维功能,而不必对代码做大的改动。当图层被动画使,一个 CATransition
或CAAnimation
对象会被附加在图层上。然后图层会调用Quartz Core,分支出一个新线程,负责动画的全部图形处理工作。开发者秩序加入期望的动画,就可以提升一个现有图层的功能。用下面的例子代码,可以创建一个转场:
[java] viewplaincopy
1 CATransition* animation = [[CATransition alloc]init];
2 animation.duration =1.0;
3 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
4 animation.type = kCATransitionPush;
5 animation.subtype = kCATransitionFromRight;
警告:到目前为止,恶心的的苹果允许用户创建的转场类型仍然极其有限。Quartz Core
框架内部还支持相当多的其他转场效果,例如自然翻页和缩放转场等,但是受到限制,只能有苹果自己的应用程序使用。(恶心吧)
通过创建一个CABasicAnimation
对象,你就可以创建出一个动画。下面的例子创建了一个动画,将图层旋转了整整360度:
[java] viewplaincopy
1 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
2 animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.1415, 0, 0, 1.0)];
3 animation.duration =3.0;
4 animation.cumulative =YES;
5 animation.repeatCount=2;
创建好之后,你可以直接将动画或者转场应用到一个图层上:
[java] viewplaincopy
1 [mapView.layer addAnimation:animation forKey:@"animation"];
八、图层变换
QuartzCore 的渲染能力可以像三维一样对二维图像进行任意操纵。一个图像可以在x-y-z
三维轴上进行任意角度旋转、缩放和扭曲。CATransform3D
函数族是苹果的Cover Flow
技术以及 iPhone
上使用的其他美观特效的幕后力量。iPhone
支持包括缩放、旋转、仿射、平移等。
变换实在单独的图层上执行的,因此多个变换可以在一个图层表面上同时进行。Quartz Core
框架用 CATransform3D
对象来执行变换。这个对象作用于视图的图层,根据期望的三维设置对图层进行弯折或者其他操作。
应用程序可以仍然将对象看作是二维的,但是当对象呈现给用户时,会遵从已经作用于图层之上的任何变换。下面的例子创建了一个变换,目的是对一个图层进行旋转:
[java] viewplaincopy
1 CATransform3D myTransform;
2 myTransform = CATransform3DMakeRotation(angle,x,y,z);
CATransform3DMakeRotation 函数创建了一个变换,对一个图形进行旋转,旋转角度angle
单位为弧度,轴为 x-y-z
。x-y-z
的值定义了轴上在各个方向上的度量(介于-1和+1之间)。在一个轴上赋予值,就会指示变换绕该轴进行旋转。可以把这些值看作是插在图像上的草棍。如果草棍是沿着
x 轴插进去的,那么图像将绕着草棍垂直旋转。你可以使用不同角度值作为轴,产生出更复杂的转动。不过对于大多数用途来说,用-1
和 +1
这两个值就够了。
要将一个图层绕水平轴转动(垂直转动)45度,可以使用下面的代码:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation(0.78,1.0,0.0,0.0);//0.78 是角度45度换成弧度得到的
要在水平方向上转动同样的角度,可以换成 y
轴指定一个值:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation(0.78,0.0,1.0,0.0);
你可以自己编写一个角度转弧度的函数:
[java] viewplaincopy
1 double radians(float degrees){
2 return (degrees*3.14159265)/180.0;
3 }
当你创建的时候就调用这个函数:
[java] viewplaincopy
1 myTransform = CATransform3DMakeRotation( radians(45.0),0.0,1.0,0.0);
变换创建完毕之后,就要作用于你要操纵的图层了。CALayer
对象提供了一个 transform属性,可以用来将变换附加到图层之上。图层将会执行任何赋予这个属性的变换:
[java] viewplaincopy
1 roleView.layer.transform = myTransform;
当这个对象被显示出来时,会按照应用在他上面的变换进行显示。在你的代码里,还是会将这个对象作为一个二维物体来引用,但是他会根据变换来进行渲染。
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- Validform+layer实现漂亮的表单验证特效
- 小巧强大的jquery layer弹窗弹层插件
- 讲解iOS开发中基本的定位功能实现
- iOS中定位当前位置坐标及转换为火星坐标的方法
- js判断客户端是iOS还是Android等移动终端的方法
- iOS应用开发中AFNetworking库的常用HTTP操作方法小结
- iOS应用中UISearchDisplayController搜索效果的用法
- iOS App开发中的UISegmentedControl分段组件用法总结
- IOS开发环境windows化攻略
- iOS应用中UITableView左滑自定义选项及批量删除的实现
- iOS中UIAlertView警告框组件的使用教程
- 浅析iOS应用开发中线程间的通信与线程安全问题
- iOS中的UIKeyboard键盘视图使用方法小结