UIView 表示屏幕上的一块矩形区域,负责渲染区域的内容,而且响应该区域内发生的触摸事件。它在 iOS App 中占有绝对重要的地位,由于 iOS 中几乎全部可视化控件都是 UIView 的子类。程序员
UIView 能够负责如下几种任务:设计模式
UIView 是按需绘制的,当整个视图或者视图的一部分因为布局变化,变成可见的,系统会要求视图进行绘制。对于那些须要使用 UIKit 或者 CoreGraphics 进行自定义绘制的视图,系统会调用 drawRect:
方法进行绘制。数组
当视图内容发生变化时,须要调用 setNeedsDisplay
或者 setNeedsDisplayInRect:
方法,告诉系统该从新绘制这个视图了。调用这个方法以后,系统会在下一个绘制周期更新这个视图的内容。因为系统要等到下一个绘制周期才真正进行绘制,能够一次性对多个视图调用 setNeedsDisplay
,它们会同时被更新。app
视图有 frame,center,bounds 等几个基本几何属性,其中:iview
视图在初次绘制完成后,系统会对绘制结果进行快照,以后尽量地使用快照,避免从新绘制。若是视图的几何属性发生改变,系统会根据视图的 contentMode 来决定如何改变显示效果。函数
默认的 contentMode 是 UIViewContentModeScaleToFill
,系统会拉伸当前的快照,使其符合新的 frame 尺寸。大部分 contentMode 都会对当前的快照进行拉伸或者移动等操做。若是须要从新绘制,能够把 contentMode 设置为 UIViewContentModeRedraw
,强制视图在改变大小之类的操做时调用drawRect:
重绘。布局
能够以动画的形式改变视图的下面这些属性,只须要告诉系统动画开始和结束时的数值,系统会自动处理中间的过渡过程。动画
frame
bounds
center
transform
alpha
backgroundColor
contentStretch
除了提供视图自己的内容以外,一个视图也能够表现得像一个容器。当一个视图包含其余视图时,两个视图之间就建立了一个父子关系。在这个关系中子视图被称为 subView ,父视图被称为 superView 。一个视图能够包含多个子视图,它们被存放在这个视图的 subviews
数组里。添加,删除,以及操做这些子视图的相对位置的函数以下:ui
addSubview:
insertSubview:...
bringSubviewToFront:
sendSubviewToBack:
exchangeSubviewAtIndex:withSubviewAtIndex:
removeFromSuperview(子视图调用)
当一个视图的大小改变时,它的子视图的位置和大小也须要相应地改变。UIView 支持自动布局,也能够手动对子视图进行布局。spa
当下列这些事件发生时,须要进行布局操做:
setNeedsLayout
或layoutIfNeeded
方法setNeedsLayout
方法视图的autoresizesSubviews
属性决定了在视图大小发生变化时,如何自动调节子视图。
可使用的掩码以下:
UIViewAutoresizingNone
UIViewAutoresizingFlexibleHeight
UIViewAutoresizingFlexibleWidth
UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleRightMargin
UIViewAutoresizingFlexibleBottomMargin
UIViewAutoresizingFlexibleTopMargin
能够经过位运算符将它们组合起来,例如 UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth
。
Constraint 是另外一种用于自动布局的方法。本质上,Constraint 就是对 UIView 之间两个属性的一个约束:
attribute1 == multiplier × attribute2 + constant
其中方程两边不必定是等于关系,也能够是大于等于之类的关系。
Constraint 比 AutoResizing 更加灵活和强大,能够实现复杂的子视图布局。
UIView 当中提供了一个 layoutSubviews
函数,UIView 的子类能够重载这个函数,以实现更加复杂和精细的子 View 布局。
苹果文档专门强调了,应该只在上面提到的 Autoresizing 和 Constraint 机制不能实现所须要的效果时,才使用 layoutSubviews
。并且,layoutSubviews 方法只能被系统触发调用,程序员不能手动直接调用该方法。
那么 layoutSubviews 方法具体调用的时机有哪些呢?具体有下面几种状况:
UIView 是 UIResponder 的子类,能够响应触控事件。
一般可使用 addGestureRecognizer:
添加手势识别器来响应触控事件,若是须要手动处理,则按须要重载 UIView 中的下面四个函数:
touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:
UIViewController(视图控制器),顾名思义,是 MVC 设计模式中的控制器部分。UIViewController 在 UIKit 中主要功能是用于控制画面的切换,其中的 view
属性(UIView 类型)管理整个画面的外观。
ViewController 生命周期的第一步是初始化。不过具体调用的方法还有所不一样。若是使用 StoryBoard 来建立 ViewController,咱们不须要显式地去初始化,Storyboard 会自动使用 initWithCoder:
进行初始化。若是不使用 StoryBoard,咱们可使用 init:
函数进行初始化,init:
函数在实现过程当中还会调用 initWithNibName:bundle:
。 咱们应该尽可能避免在 VC 外部调用 initWithNibName:bundle:
,而是把它放在 VC 的内部(参考这里)。
初始化完成后,VC 的生命周期会通过下面几个函数:
(void)loadView (void)viewDidLoad (void)viewWillAppear (void)viewWillLayoutSubviews (void)viewDidLayoutSubviews (void)viewDidAppear (void)viewWillDisappear (void)viewDidDisappear
假设如今有一个 AViewController(简称 Avc) 和 BViewController (简称 Bvc),经过 navigationController 的 push 实现 Avc 到 Bvc 的跳转,下面是各个方法的执行执行顺序:
1. A viewDidLoad 2. A viewWillAppear 3. A viewDidAppear 4. B viewDidLoad 5. A viewWillDisappear 6. B viewWillAppear 7. A viewDidDisappear 8. B viewDidAppear
若是再从 Bvc 跳回 Avc,会产生下面的执行顺序:
1. B viewWillDisappear 2. A viewWillAppear 3. B viewDidDisappear 4. A viewDidAppear
可见 viewDidLoad 只会调用一次,再第二次跳回 Avc 的时候,AViewController 仍然存在于内存中,也就不须要 load 了。
注意上面的生命周期中都没有提到有关 ViewController 销毁的内容,在 iOS 4 & 5 中 ViewController 中有一个 viewDidUnload
方法。当内存不足,应用收到 Memory warning 时,系统会自动调用当前没在界面上的 ViewController 的 viewDidUnload 方法。 一般状况下,这些未显示在界面上的 ViewController 是 UINavigationController Push 栈中未在栈顶的 ViewController,以及 UITabBarViewController 中未显示的子 ViewController。这些 View Controller 都会在 Memory Warning 事件发生时,被系统自动调用 viewDidUnload 方法。
从 iOS 6 开始,viewDidUnload 方法被废弃掉了,应用受到 memory warning 时也不会再调用 viewDidUnload 方法。咱们能够经过重载 - (void)didReceiveMemoryWarning
和 -(void)dealloc
来进行清理工做。