最近切实的感觉到了本身在界面这一块基础原理的匮乏,所以决定深刻学习了解一下Core Animation, 可是在学习Core Animation的开端,不由又怀疑本身,UIWindow是什么?它的做用你真的明白吗?为何要有UIWindow呢,若是没有的话行不行呢?一系列问题层出不穷,所以我决定在研究学习Core Animation以前去学习学习苹果的官方文档View Programming Guide for iOS, 那么在开始的这一篇我只会去写一写我对于UIView的学习,总结,应该还会有一些问题,但愿和你们一块儿交流交流。html
可能在文中会用到不一样的词,可是他们是一个含义:
view == view对象 == 视图对象 == UIView对象
window == window对象 == 视窗对象 == UIWindow对象
(注:UIWindow的基类是UIView)
复制代码
View
究竟是什么?View
对象在屏幕上定义了一块矩形的区域而且处理这个区域内部的事件。在UIKIT
中,每个UIView对象
都有一个CALayer对象
的layer属性,layer对象
负责视图内容的绘制,处理视图动画相关的事宜。视图由layer绘制,动画也由layer处理,那么UIView对象
作什么呢?其实UIView对象
能够理解为是对layer
的封装,提供了处理触摸事件的具体功能以及Core Animation
底层方法的接口。面试
Core Animation
呢?Core Animation
是是iOS和OSX上可用的图形渲染和动画基础结构,用于为应用的视图和其余视觉元素设置动画。它把大量的绘图工做交给GPU去加速渲染,因此能够实现高帧率高流畅度的动画效果,并不会去负载CPU而使得手机卡顿。数组
Core Animation 并非一个绘图系统,而是使用硬件去合成和处理视图内容的基础框架,而这个基础框架的核心就是layer对象
,那么layer
又是如何对视图内容进行处理的呢?它会将其转化为GPU便宜处理的bitmap,而后GPU再去执行相应的操做,大多数APP中layer都是用来管理视图内容的,可是也能够去单独的建立独立的layer。bash
那么如今能够对Core Animation
能够进行一些底层的了解了:markdown
Core Animation是一套包含图形绘制、投影、动画的Objective-C类集合,该框架包含在QuartzCore.framework中. app
![]()
上图的OpenGL ES是一个C语言写的很是底层的图形处理框架。是个移动设备上绘制2D和3D计算机图形的标准的开源库,普遍地被用在游戏的图形的绘制上负责直接驱动GPU,效率很高,可是使用起来很复杂。框架
Core Animation的核心就是对于OpenGL ES的抽象,它并不作渲染工做,而是使用OpenGL ES的功能,让GPU去处理渲染。从上图的结构能够知道Core Graphic 的绘制是须要消耗CPU的,而Core Animation渲染消耗的是GPU。Core Animation最繁重的任务是去判断出哪些layer须要被从新绘制,而OpenGL ES要作的就是将layer合并、显示在屏幕上。ide
Core Graphic, Core Animation, Core Image是三个不一样的核心库,它们之间可能会有交互,可是不存在一个包含的关系。上图是它们的工做流程图oop
当你设置一个 layer 的内容为 CGImageRef 时,Core Animation 会建立一个 OpenGL 纹理,并确保在这个图层中的位图被上传到对应的纹理中。以及当你重写 -drawInContext 方法时,Core Animation 会请求分配一个纹理,同时确保 Core Graphics 会将你所作的(即你在drawInContext中绘制的东西)放入到纹理的位图数据中。一个layer的属性和 CALayer 的子类会影响到 OpenGL 的渲染结果,许多底层的 OpenGL ES 行为被简单易懂地封装到 CALayer 概念中。布局
好了,走偏了咱们仍是继续聊一聊UIView吧。
每个父视图都会维持一个子视图数组,在数组最后一个子视图就是最上层的子视图,若是子视图重叠了,数组中靠后的子视图位于上方,父视图和子视图的关系会影响子视图的显示,在代码中常见的有两个场景
//1. 要求子视图不透明,父视图透明 layerView.backgroundColor = UIColor.black.withAlphaComponent(0.1) //2. scrollView自动调整子视图size如何解决? let scrollView = UIScrollView.init(frame: CGRect.init(x: 0, y: 0, width: 100, height: 100)) scrollView.autoresizesSubviews = false 复制代码
当谈及UIView和CALayer的主要区别时,最重要的区别就是UIView是能够响应事件的,那么View是如何响应事件的呢?简单来说分为两步:
- 寻找发生触摸事件的视图(从上往下)
- 找到事件的第一响应者(从下往上)
![]()
当view第一次在屏幕上显示的时候,系统会绘制它的内容,而后系统会截取内容的快照,而且将快照做为视图的可见外观,若是你永远不改变视图的内容,那么视图的绘制代码永远不会改变。若是更改了视图的内容,不用直接从新绘制,而是使用setNeedsDisplay
或者setNeedsDisplayInRect
方法是视图无效。这些方法会告知视图内容以及改变而且须要在下一次进行重绘。若是须要立马重绘,那么须要使用layoutIfNeeded
方法。
有时候只须要可视视图的一部份能够被伸缩,这个在设置按钮背景图片的场景是很是常见的,那么如何让这个常见的需求实现呢?使用resizableImageWithCapInsets:
方法,能够肯定可缩放的视图的内容,以下:
var image = UIImage.init(named: "image.png") image = image?.resizableImage(withCapInsets: UIEdgeInsetsMake(10, 10, 10, 10), resizingMode: UIImageResizingMode.stretch) let imageview = UIImageView.init(image: image) 复制代码
伸缩背景的效果以下:(使四个角不变,中心进行缩放)
视图能够实现的动画效果的属性以下:
UIKit的坐标系以屏幕的左上角为原点
那么window的职责是什么,为何要有Window的存在呢?没有Window行不行呢? 下面试官网的原文
* It contains your application’s visible content. * It plays a key role in the delivery of touch events to your views and other application objects. * It works with your application’s view controllers to facilitate orientation changes. 复制代码
若是把viewController拿出来看,咱们知道viewController通常对应着相应的应用内部模块,若是要和其余的应用交互呢?这个就须要靠Window
了;固然还有一点是屏幕的方向,这个也是经过Window
来控制的!
在大多数时候,咱们只须要在didFinishLaunchingWithOptions:
中初始化window以后就不会去涉及其余的window操做了,若是使用IB的话,连window的初始化也没有必要了;可是在实际的代码过程当中仍然可能会涉及两个任务
其实吧,分屏是一个很是常见的功能,若是接触过度屏的话就须要去仔细的研究研究分屏相关的代码,这一块也是和UIWindow息息相关的。
在布局中有一个很讨厌的事情,就是明明你的frame都已经设定好了,可是依然在运行的时候就会发生变化,其实不少这种状况的缘由就是被添加的子视图的frame会随着父视图的frame的变化而发生变化;其二就是有时候子视图须要保持和父视图一致的大小变换,或者维持原有的尺寸不变,这个时候就须要视图的自动化调整布局了。
父视图的 autoresizesSubviews
属性决定全部子视图是否须要调整。若是属性设置为 YES,视图会使用每一个子视图的 autoresizingMask
属性决定子视图的位置和尺寸。每一个子视图的尺寸变动会对它们的子视图触发一样的布局调整。每个子视图的autoresizingMask
属性如何决定呢?
UIViewAutoresizingFlexibleHeight
当父视图高度变动时视图的高度也变动。若是这个常量没被包含,视图的高度将不会变动。UIViewAutoresizingFlexibleWidth
当父视图宽度变动时视图的宽度也变动。若是这个常量没被包含,视图的宽度将不会变动。UIVIewAutoresizingFlexibleLeftMargin
视图的左边缘和父视图的左边缘之间的距离根据须要增加或缩短。若是这个常量没有设置,视图的左边缘与父视图的左边缘之间的距离保持固定。UIViewAutoresizingFlexibleRightMargin
视图的右边缘和父视图的右边缘之间的距离根据须要增加或缩短。若是这个常量没有设置,视图的右边缘与父视图的右边缘之间的距离保持固定。UIViewAutoresizingFlexibleBottomMargin
视图的底部边缘和父视图的底部边缘之间的距离根据须要增加或缩短。若是这个常量没有设置,视图的底部边缘与父视图的底部边缘之间的距离保持固定。UIViewAutoresizingFlexibleTopMargin
视图的顶部边缘和父视图的顶部边缘之间的距离根据须要增加或缩短。若是这个常量没有设置,视图的顶部边缘与父视图的顶部边缘之间的距离保持固定。在使用code时: initWithFrame: 在使用nib时: initWithCoder: -> awakeFromNib
在实际的操做中,要尽可能少的使用drawRect:方法,若是要使用此方法,明确它的职责:绘制内容。使用的时候要配置环境,绘制内容,尽量快结束绘制。 提升绘制性能的两个小tips:
这个就很是常见了,大多使用的是UIView自带的Block动画,这个就不在细聊了,有一点想提一提,就是普通的动画只能是从A -> B两种状态之间进行切换,若是加上交互的话,动画就会变得不流畅了,因此Apple在iOS10添加了一个新的特性:UIViewPropertyAnimator ,这个在后面再聊吧。
也不知道为何写了这么多,其实写的时候,主要仍是不少东西都是有关联的,一旦深刻其实还会有很是多的东西在里面,以上是个人学习和一些总结。若是写的很差,欢迎指出问题,这样我就能够慢慢改进了,下一篇,我会用比较短的篇幅聊一聊UIViewController,而后就正式的进入个人Core Animation的学习过程当中了。