UIView与UIWindow,UIRespnder那些事儿
UIView与UIWindow
-
Uiview需要一个窗口UIWindow来展示页面,而UIWindow类似于一个Uiview.
- 1.调用[parentView addSubview:childview]来添加基于该视图或者该窗口的子视图,新创建的视图顺序显示在最前面.
- 2.调用[parentView subviews]来查询基于该视图或者该窗口下的所有的子视图.顺序为从后到前, 即添加顺序.
- 3.调用[view removeFromSuperview]可以从该主视图(可以是窗口)中删除.
- 4.调用[parentView exchangeSubviewAtIndex:I withSubviewAtIndex:j]来重新派讯,修改j索引下的子视图为i索引.也可以使用bringSubviewToFront:或者sendSubviewToBack:将视图前移或者后移.
- 5.使用setTag:给子视图添加标记.做这个标记可以在父视图中调用[parentView viewWithTag:]可以搜索到该标记的子视图.也可以作为一个区分的意思(当前太多视图或者控件时候).
-
UIWindow的作用:
- 和Mac OS X的应用程序有所不同,iPhone应用程序通常只有一个窗口,表示为一个UIWindow类的实例。您的应用程序在启动时创建这个窗口(或者从nib文件进行装载),并往窗口中加入一或多个视图,然后将它显示出来。窗口显示出来之后,您很少需要再次引用它。
- 在iOS中,窗口对象并没有像关闭框或标题栏这样的视觉装饰,用户不能直接对其进行关闭或其它操作。所有对窗口的操作都需要通过其编程接口来实现。应用程序可以借助窗口对象来进行事件传递。窗口对象会持续跟踪当前的第一响应者对象,并在UIApplication对象提出请求时将事件传递它。
- UIWindow类的继承关系。在Mac OS X中,NSWindow的父类是NSResponder;而在iOS中,UIWindow的父类是UIView。因此,窗口在iOS中也是一个视图对象。不管其起源如何,您通常可以将iOS上的窗口和Mac OS X的窗口同样对待。也就是说,您通常不必直接操作UIWindow对象中与视图有关的属性变量。
- 在创建应用程序窗口时,您应该总是将其初始的边框尺寸设置为整个屏幕的大小。如果您的窗口是从nib文件装载得到,Interface Builder并不允许创建比屏幕尺寸小的窗口;然而,如果您的窗口是通过编程方式创建的,则必须在创建时传入期望的边框矩形。除了屏幕矩形之外,没有理由传入其它边框矩形。屏幕矩形可以通过UIScreen对象来取得,具体代码如下所示:
UIWindow* aWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
-
虽然iOS支持将一个窗口叠放在其它窗口的上方,但是您的应用程序永远不应创建多个窗口。系统自身使用额外的窗口来显示系统状态条、重要的警告、以及位于应用程序窗口上方的其它消息。如果您希望在自己的内容上方显示警告,可以使用UIKit提供的警告视图,而不应创建额外的窗口。
-
UIView是作用
-
视图是UIView类的实例,负责在屏幕上定义一个矩形区域。在iPhone的应用程序中,视图在展示用户界面及响应用户界面交互方面发挥关键作用。每个视图对象都要负责渲染视图矩形区域中的内容,并响应该区域中发生的触碰事件。这一双重行为意味着视图是应用程序与用户交互的重要机制。在一个基于模型-视图-控制器(MVC)的应用程序中,视图对象明显属于视图部分。
-
除了显示内容和处理事件之外,视图还可以用于管理一或多个子视图。子视图是指嵌入到另一视图对象边框内部的视图对象,而被嵌入的视图则被称为父视图或超视图。视图的这种布局方式被称为视图层次,一个视图可以包含任意数量的子视图,通过为子视图添加子视图的方式,视图可以实现任意深度的嵌套。视图在视图层次中的组织方式决定了在屏幕上显示的内容,原因是子视图总是被显示在其父视图的上方;这个组织方法还决定了视图如何响应事件和变化。每个父视图都负责管理其直接的子视图,即根据需要调整它们的位置和尺寸,以及响应它们没有处理的事件。
-
由于视图对象是应用程序和用户交互的主要途径,所以需要在很多方面发挥作用,下面是其中的一小部分:
- 描画和动画
- 视图负责对其所属的矩形区域进行描画。
- 某些视图属性变量可以以动画的形式过渡到新的值。
- 布局和子视图管理
- 视图管理着一个子视图列表。
- 视图定义了自身相对于其父视图的尺寸调整行为。
- 必要时,视图可以通过代码调整其子视图的尺寸和位置。
- 视图可以将其坐标系统下的点转换为其它视图或窗口坐标系统下的点。
- 事件处理
- 视图可以接收触摸事件。
- 视图是响应者链的参与者。
- 描画和动画
-
在iPhone应用程序中,视图和视图控制器紧密协作,管理若干方面的视图行为。视图控制器的作用是处理视图的装载与卸载、处理由于设备旋转导致的界面旋转,以及和用于构建复杂用户界面的高级导航对象进行交互。
- UIKit的视图类
- UIView类定义了视图的基本行为,但并不定义其视觉表示。相反,UIKit通过其子类来为像文本框、按键、及工具条这样的标准界面元素定义具体的外观和行为。
- 除了UIView和UIControl类是例外,这个框图中的大多数视图都设计为可直接使用,或者和委托对象结合使用。
CALayer
- CALayer直接继承于NSObject,因为缺少UIResponder的支持,所以CALayer不能响应任何用户事件
- 每个UIView都有CALayer,即UIView.layer,其所有视觉效果都是在这个layer上进行的。可以认为UIView注重于处理用户事件,而CALayer则注重于显示效果。CALayer是绘制内容的,不处理事件响应,与UIView是相互依赖的,依赖于UIView来显示绘制内容,UIView依赖于CALayer来提供内容
UIWindow
-
UIwindow继于UIView。UIWindow对象是所有UIView的根,管理和协调应用程序的显示。
-
UIWindow类是UIView的子类,可以看作是特殊的UIView。一般应用程序只有一个UIWindow对象,但可以手动创建多个添加到程序中,即使有多个UIWindow对象,也只有一个UIWindow可以接受到用户的触屏事件。
-
UIWindow主要起三个作用:
-
一是作为容器提供一个区域来显示UIView,包含程序所有要显示的视图
-
二是将事件(event)的分发给UIView(传递触摸消息到其他的UIView或其他对象)
-
三是与UIViewController协同工作,完成设备方向旋转的支持
-
-
创建一个UIWindow:
1.创建一个全频的window
self.window = [[UIWindow alloc] initWithFram:[UIScreen mainScreen].bounds];
2.在window中放入根控制器
self.window.rootViewControl = rootViewControl;
3.将window设置为keyWindow并显示window
[self.window makeKeyAndVisible];
- 获取当前的keyWindow
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
- UIScreen可以看成就是手机屏幕,它提供了一个画布,可以在上面画各种视图控件,可以通过[[UIScreen mainScreen] bounds]来获取屏幕尺寸.
iphone屏幕分辨率:
iphone4前的设备:320*480
iphone4和4s:640*960
iphone5和5s:640*1136
iphone6:750*1334
iphone6p:1242*2208
ipad ipad2:1024*768
ipad3和4 ipad4:2048*1536
ipad mini:1024*768
UIView
- UIView对象定义了一个屏幕上的一个矩形区域,同时处理该区域的绘制和触屏事件。
- 可以在这个区域内绘制图形和文字,还可以接收用户的操作。一个UIView的实例可以包含和管理若干个子UIView。
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 100, 100)];
myView.backgroundColor=[UIColor redColor];
[self.view addSubview:myView];
}
- UIView中常用的结构体:
CGPoint point = CGPointMake(x,y);//左上角坐标的位置
CGSize size = CGSizeMake(width,height);//大小
CGRect rect = CGRectMake(x,y,width,height);//位置和大小 ```
- UIView的常用属性:
```objc
frame: 相对父视图的位置和大小
bounds:相对自身的位置和大小,所以bounds的x和y永远为0
center:子视图的中点坐标相对父视图的位置
transform:可以通过这个属性控制视图的放大缩小和旋转
superview:获取父视图
subviews:获取所有子视图
alpha:视图的透明度(0-1)
tag:视图的标志,设置了tag后,可以通过viewWithTag方法拿到这个视图
userInteractionEnabled:是否响应用户事件
- 通过transform属性来对视图进行缩放,旋转
CGAffineTransform transform = rootView.transform;
rootVIew.transform = CGAffineTransformMakeScale(0.5, 0.5);//缩放
rootView.transform = CGAffineTransformScale(transform,0.5,0.5)//在原来的基础上再缩放
rootView.transform = CGAffineTransformMakeRotation(M_2_PI);//旋转传入的角度是弧度制的
rootView.transform = CGAffineTransformRotate(transform,M_PI_4);
rootView.transform = CGAffineTransformMakeTranslation(100, 100);//平移
rootView.transform = CGAffineTransformTranslate(transform, 100, 100);
- UIView的常用方法:
- (void)removeFromSuperview;将视图从父视图中移除
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;插入一个视图到指定位置,视图越在下面,index越小
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;将index1和index2位置的两个视图互换位置
- (void)addSubview:(UIView *)view;添加视图到父视图
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;插入视图到指定视图的下面
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;插入视图到指定视图上面
- (void)bringSubviewToFront:(UIView *)view;把视图移到最顶层
- (void)sendSubviewToBack:(UIView *)view;把视图移到最底层
- (UIView *)viewWithTag:(NSInteger)tag; 根据视图的tag属性找到搜索视图
- 通过UIView的属性产生一些基本动画
UIVIew中支持动画的属性有以下几个:
frame:可以通过frame来改变视图的尺寸和位置
bounds:可以通过bounds来改变视图的尺寸
center:可以通过center来改变视图的位置
transform:可以通过transform来使视图翻转和缩放,平移
alpha:可以通过alpha修改视图的透明度
backgroundColor:改变视图的背景颜色
contentStetch:改变视图内容如何拉伸
1.
[UIView beginAnimations:nil context:nil];//开始动画
[UIView setAnimationDuration:2];//持续时间
//动画
CGAffineTransform transform = sender.transform;
sender.transform = CGAffineTransformMakeTranslation(100, 100);
sender.transform = CGAffineTransformTranslate(transform, 100, 100);
[UIView commitAnimations];//提交动画
2.使用block
[UIView animateWithDuration:2 animations:^{
CGAffineTransform transform = sender.transform;
sender.transform = CGAffineTransformMakeTranslation(100, 100);
sender.transform = CGAffineTransformTranslate(transform, 100, 100);
}];
3.使用block
[UIView animateWithDuration:2 animations:^{
CGAffineTransform transform = sender.transform;
sender.transform = CGAffineTransformMakeTranslation(100, 100);
sender.transform = CGAffineTransformTranslate(transform, 100, 100);
} completion:^(BOOL finished) {
//动画完成后调用的代码段
}];
动画常用设置
[UIView setAnimationDuration:2];动画持续时间
[UIView setAnimationRepeatCount:1];动画重复次数
-
UIViewController负责创建其管理的视图及在低内存的时候将他们从内存中移除。还为标准的系统行为进行响应。
-
UIViewController负责管理所有UIView的层次结构,并响应设备的方向变化。
-
UIView的setNeedsDisplay和setNeedsLayout方法
- 1、在Mac OS中NSWindow的父类是NSResponder,而在iOS 中UIWindow 的父类是UIVIew。程序一般只有一个窗口但是会又很多视图。
- 2、UIView的作用:描画和动画,视图负责对其所属的矩形区域描画、布局和子视图管理、事件处理、可以接收触摸事件、事件信息的载体、等等。
- 3、UIViewController 负责创建其管理的视图及在低内存的时候将他们从内存中移除。还为标准的系统行为进行响应。
- 4、layOutSubViews 可以在自己定制的视图中重载这个方法,用来调整子视图的尺寸和位置。
- 5、UIView的setNeedsDisplay和setNeedsLayout方法
- 首先两个方法都是异步执行的。而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画了。
- 而setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据。
- 综上所述:setNeedsDisplay方便绘图,而layoutSubViews方便出来数据
- setNeedDisplay告知视图它发生了改变,需要重新绘制自身,就相当于刷新界面.
- layoutSubviews在以下情况下会被调用:
- 1、init初始化不会触发layoutSubviews。
- 2、addSubview会触发layoutSubviews。
- 3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
- 4、滚动一个UIScrollView会触发layoutSubviews。
- 5、旋转Screen会触发父UIView上的layoutSubviews事件。
- 6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
- 7、直接调用setLayoutSubviews。
- drawRect在以下情况下会被调用:
- 1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).
- 2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
- 3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
- 4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
以上1,2推荐;而3,4不提倡
- drawRect方法使用注意点
- 1、若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个 invalidate的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或者 setNeedsDisplayInRect,让系统自动调该方法。
- 2、若使用calayer绘图,只能在drawInContext: 中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法
- 3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕
- layoutSubviews在以下情况下会被调用:
-
initWithFram:(CGRect)frame方法用来初始化一个UIView,传入CGRect当参数
UIRespnder
- UIResponder 是 UIView 的父类。responder 能够处理触摸、手势、远程控制等事件。
- 之所以它是一个单独的类而没有合并到 UIView 中,是因为 UIResponder 有更多的子类,最明显的就是 UIApplication 和 UIViewController。
- 通过重写 UIResponder的方法,可以决定一个类是否可以成为第一响应者 (first responder),例如当前输入焦点元素。
- 当 touches (触摸) 或 motion (指一系列运动传感器) 等交互行为发生时,它们被发送给第一响应者 (通常是一个视图)。
- 如果第一响应者没有处理,则该行为沿着响应链到达视图控制器,如果行为仍然没有被处理,则继续传递给应用。
- 如果想监测晃动手势,可以根据需要在这3层中的任意位置处理。
- UIResponder 还允许自定义输入方法,从 inputAccessoryView 向键盘添加辅助视图到使用 inputView 提供一个完全自定义的键盘。