UIView、UIWindow简介

UIView和UIWindow展示了应用的用户界面,同时负责界面的交互。其中UIView表示屏幕上的一块矩形区域,它在App中占有绝对重要的地位,因为IOS中几乎所有可视化控件都是UIView的子类。负责渲染区域的内容,并且响应该区域内发生的触摸事件。

一、UIView简介

1.UIView功能及视图层次

UIView的功能 

1.管理矩形区域里的内容

2.处理矩形区域中的事件

3.子视图的管理 

4.实现动画

UIView的视图层次


UIView、UIWindow简介_第1张图片
UIView视图层次图

2.UIView生命周期

UIView初始化方法

- (instancetype)initWithFrame:(CGRect)frame通过frame初始化UIView,也是官方推荐初始化方法。

- (nullable instancetype)initWithCoder:(NSCoder*)aDecoder如果使用NIB文件,使用此方法初始化。

UIView生命周期

(loadView/nib)文件来加载view到内存-->viewDidLoad函数进一步初始化这些view-->内存不足时, 调用viewDidUnload函数释放views-->当需要使用view时又回到第一步

loadView:

永远不要主导调用这个函数。viewController 会在view的property被请求并且当前view值为nil时调用这个函数。如果你手动创建view, 你应该重载这个函数,切不要在重载的时候调用[super loadView]。

viewDidload:

开发者可以进一步的初始化其views。viewDidLoad通常负责的是view及其子view被加载进内存之后的数据初始化的工作,即视图的数据部分的初始化

viewDidUnLoad:

viewDidLoad的对立函数,在程序内存欠缺时,这个函数被controller调用,来释放他的view以及view相关的对象。由于controller通常保存着view以及相关的object的引用,所以你必须使用这个函数来放弃这些对象的所有权以便内存回收,但不要释放那些难以重建的数据

viewWillAppear:

视图即将可见时调用,默认情况下不执行任何操作。

viewDidAppear:

视图已完全过渡到屏幕上时调用

viewWillDisappear:

视图被驳回时调用,覆盖或以其他方式隐藏,默认情况下不执行任何操作

viewDidDisappear:

视图被驳回后调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作

didReceiveMemoryWarning:

当程序内存过度时,系统会调用该方法

3.UIView常用属性

三个结构体

struct CGPoint{CGFloat x;CGFloat y;};

struct CGSize{CGFloat width;CGFloat height;};

struct CGRect{CGPoint origin;CGSize size;};

最基本属性

frame是CGRect frame的origin是相对于父视图的左上角原点(0,0)的位置,改变视图的frame会改变center

center是CGPoint指的就是整个视图的中心点,改变视图的center也会改变frame

bounds是CGRect是告诉子视图本视图的原点位置(通俗的说就是,子视图的frame的origin与父视图的bounds的origin的差,就是子视图相对于父视图左上角的位置,如果结果为负,则子视图在父视图外)

UIView、UIWindow简介_第2张图片
Frame和Bounds的区别

常见属性

alpha:液晶显示器是由一个个的像素点组成的,每个像素点都可以显示一个由RGBA颜色空间组成的一种色值。其中的A就表示透明度alpha,UIView中alpha是一个浮点值,取值范围0~1.0,表示从完全透明到完全不透明。

当把alpha的值设置成0以后:

1、当前的UIView和subview都会被隐藏,而不管subview的alpha值为多少

2、当前UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者

hidden:该属性为BOOL值,用来表示UIView是否隐藏,默认值是NO。

当值设为YES时:

1、当前的UIView和subview都会被隐藏,而不管subview的hidden值为多少。

2、当前UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者

opaque:表示当前UIView是否不透明,该属性为BOOL值,UIView的默认值是YES,但UIButton等子类的默认值都是NO。事实上它却决定不了当前UIView是不是不透明,比如你将opaque设为NO,该UIView照样是可见的。

UIView、UIWindow简介_第3张图片
图层混合

显示器中的每个像素点都可以显示一个由RGBA颜色空间组成的色值,比如上图中有红色和绿色两个图层色块,对于没有交叉的部分,即纯红色和绿色部分来说,对应位置的像素点只需要简单的显示红或绿,对应的RGBA为(1,0,0,1)和(0,1,0,1)就行了,负责图形显示的GPU需要很小的计算量就可以确定像素点对应的显示内容。从图中我们可以看出,重叠的部分出现了黄色,这是因为GPU会通过图层一和图层二的颜色进行图层混合,计算出混合部分的颜色,最理想情况的计算公式如下:

                                             R = S + D * ( 1 – Sa )

其中,R表示混合结果的颜色,S是源颜色(位于上层的红色图层一),D是目标颜色(位于下层的绿色图层二),Sa是源颜色的alpha值,即透明度。公式中所有的S和D颜色都假定已经预先乘以了他们的透明度。

当UIView的opaque属性被设为YES以后,按照上面的公式,也就是Sa的值为1,这个时候公式就变成了:R = S。即不管D为什么,结果都一样。因此GPU将不会做任何的计算合成,不需要考虑它下方的任何东西(因为都被它遮挡住了),而是简单从这个层拷贝。这节省了GPU相当大的工作量。按照前面的逻辑,当opaque属性被设为YES时,GPU就不会再利用图层颜色合成公式去合成真正的色值。因此,如果opaque被设置成YES,而对应UIView的alpha属性不为1.0的时候,就会有不可预料的情况发生。所以说,opaque的真实用处是给绘图系统提供一个性能优化开关!

4.UIView Animation

1.frame,bounds,center//改变View的frame属性

-(void)doChangeFrame

{

[UIView animateWithDuration:2.0 animations:^(void){

    smallImage.frame = CGRectMake(150, 80, 30, 30);

} completion:^(BOOL finished) {

    smallImage.alpha = 0;

}];

}

2.alpha //改变透明度

3.backgroundColor //改变背景颜色

4.contentStretch //拉伸变化

5.transform //仿射变换,其中又包括Rotate,Invert,Translate,Scale(旋转,反转,位移,缩放)

-(void)doRotate//旋转

{

CGAffineTransform transform=  CGAffineTransformMakeRotation(M_PI/4);

[UIView beginAnimations:nil context:nil];

bigImage.transform = transform;

[UIView commitAnimations];

}

-(void)doInvert//反转

{

BOOL isSingle = seg.selectedSegmentIndex;

//如果单次 直接翻转到原始状态 如果连续 在以前基础上再次进行反转

CGAffineTransform transform = isSingle?CGAffineTransformInvert(bigImage.transform):CGAffineTransformIdentity;

[UIView beginAnimations:nil context:nil];

bigImage.transform = transform;

[UIView commitAnimations];

}

-(void)doTranslate//位移

{

BOOL isSingle = seg.selectedSegmentIndex;

//如果单次 只改变一次 如果连续 在以前基础上再次进行移位

CGAffineTransform transform = isSingle?CGAffineTransformMakeTranslation(10, 10):CGAffineTransformTranslate(bigImage.transform, 10, 10);

[UIView animateWithDuration:1 animations:^{

bigImage.transform = transform;

}];

}

-(void)doScale//缩放

{

BOOL isSingle = seg.selectedSegmentIndex;

//如果单次 只改变一次 如果连续 在以前基础上再次进行缩放

CGAffineTransform transform = isSingle?CGAffineTransformMakeScale(1.0, 1.1):CGAffineTransformScale(bigImage.transform, 1.0, 1.1);

[UIView beginAnimations:nil context:nil];

bigImage.transform = transform;

[UIView commitAnimations];

}

关于Transition Animation可以参见这篇博文:http://www.csdn.net/article/2015-07-07/2825139-ios-uiview-animation-3

5.CALayer 和 UIView 的区别和联系

UIView之所以能显示在屏幕上,完全是因为它内部的一个图层,在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层

@property(nonatomic,readonly,retain) CALayer *layer;

当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示

换句话说,UIView本身不具备显示的功能,拥有显示功能的是它内部的图层。

a.UIView可以相应事件,Layer不可以

UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。UIApplication、UIViewController、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。

在 UIResponder中定义了处理各种事件和事件传递的接口, 而 CALayer直接继承 NSObject,并没有相应的处理事件的接口。

下面四个方法分别处理触摸开始事件,触摸移动事件,触摸终止事件,以及触摸跟踪取消事件。

– touchesBegan:withEvent:

– touchesMoved:withEvent:

– touchesEnded:withEvent:

– touchesCancelled:withEvent:

关于UIResponder的事件处理和传递机制参见以下两篇博文:

1.http://yishuiliunian.gitbooks.io/implementate-tableview-to-understand-ios/content/uikit/1-1-2.html

2.http://blog.csdn.net/chun799/article/details/8223612

b.CALayer的创建

Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。

CALayer的创建时机是在[view initWithFrame] 的时候调用私有方法【UIView _createLayerWithFrame】去创建的。

c.UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。

UIView 是 CALayer 的CALayerDelegate,在代理方法内部[UIView(CALayerDelegate) drawLayer:inContext]调用 UIView 的 DrawRect方法,从而绘制出了 UIView 的内容.

d.CALayer重用视觉效果

调整图层的大小和位置

调整图层的背景颜色

修改图层的内容 (一个图片,或者是用CoreGraphics绘制的东西)

图层是否圆角

添加黑色投影

添加描边的边框

二、UIWindow简介

在iOS App中,UIWindow是最顶层的界面内容,我们使用UIWindow和UIView来呈现界面。UIWindow并不包含任何默认的内容,但是它被当作UIView的容器,用于放置应用中所有的UIView。

从继承关系来看,UIWindow继承自UIView,所以UIWindow除了具有UIView的所有功能之外,还增加了一些特有的属性和方法,而我们最常用的方法,就是在App刚启动时,调用UIWindow的makeKeyAndVisible方法,代码如下:

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

self.window= [[UIWindowalloc] initWithFrame:[[UIScreen mainScreen] bounds]];

HomeNavigationController *viewController = [HomeNavigationController sharedNavigationController];

self.window.rootViewController= viewController;

[self.windowmakeKeyAndVisible];

returnYES;

}

总的来看,UIWindow的主要作用有:

1.作为UIView的最顶层容器,包含应用显示所有的UIView;

2.传递触摸消息和键盘事件给UIView;

UIWindow添加UIView

通常有两种方式向UIWindow中添加UIView:

1.通过调用addSubView方法,因为UIWindow是UIView的子类,所以它可以使用UIView的addSubView方法给自己增加子UIView,从而承担容器的作用;

2.通过设置其特有的rootViewController属性。设置该属性后,UIWindow会自动将view controller的view添加到当前window中,同时负责维护view controller和view的生命周期。上述在application:didFinishLaunchingWithOptions:中使用的就是这种办法;

UIWindow的使用

通常在一个程序中只会有一个UIWindow,但有些时候我们调用系统的控件(例如UIAlertView)时,iOS系统为了保证UIAlertView在所有的界面之上,它会临时创建一个新的UIWindow,通过将其UIWindowLevel设置更高,让UIAlertView盖在所有其他UI之上。

UIWindow的层级由一个UIWindowLevel类型属性windowLevel,该属性指示了UIWindow的层级,windowLevel有三种可取值:

UIKIT_EXTERNconstUIWindowLevel UIWindowLevelNormal;

UIKIT_EXTERNconstUIWindowLevel UIWindowLevelAlert;

UIKIT_EXTERNconstUIWindowLevel UIWindowLevelStatusBar;

从中能够看出,默认程序的UIWindow的层级是UIWindowLevelNormal,当系统需要覆盖在其上覆盖UIAlertView时,就会创建一个层级是UIWindowLevelAlert的UIWindow,因为其windowLevel值更高,所以就覆盖在上面了

有些时候,我们也希望在应用开发中,将某些界面覆盖在所有界面的最上层。这个时候,我们就可以手工创建一个新的UIWindow。需要注意的是,和创建UIView不同,UIWindow一旦被创建,它就自动地被添加到整个界面上了(当然,其windowLevel要足够高)。

还有一点需要注意的是,如果我们创建的UIWindow需要处理键盘事件,那就需要合理地将其设置为keyWindow。keyWindow是被系统设计用来接收键盘和其他非触摸事件的UIWindow。我们可以通过makeKeyWindow和resignKeyWindow方法设置UIWindow实例的keyWindow与否。

唐巧在《iOS开发进阶》里的描述,支付宝钱包等App的密码保护页面是基于UIWindow实现的,当用户从应用的任何界面按Home键退出,过一段时间再从后台切换回来时,显示一个密码输入界面。只有用户输入了正确的密码,才能进入退出前的界面。因为这个密码输入界面可能从任何应用界面弹出,并且需要盖住所有界面的最上层,所以很合适做一个UIWindow来实现。

UIWindow的获取

1.通过[UIApplication sharedApplication].windows  获取在应用中打开的UIWindow列表,可以获取应用中的任何一个UIView对象,例如 当输入文字时,弹出的键盘就是UIWindow,如果需要改变键盘的样式,则可用更改当前Window。

2.通过[UIApplication sharedApplication].keyWindow获取应用程序的主窗口,用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是keyWindow。

3.通过view.window获得某个UIView所在的UIWindow

你可能感兴趣的:(UIView、UIWindow简介)