一、View和Window简介
在iOS中,我们用window和view来呈现应用的内容。事实上window本身不能呈现任何可视的内容,但是它可以为view提供基本的容器功能。view相当于定义了window中的一块用于显示内容的区域。例如:用来显示图片、文字、图形或者以上几者的组合的view。你也可以用view来组织和管理其他view。
每个应用都至少有一个window和一个view组成。UIKit和其他系统框架提供了一些预定义的view:从最简单的button、text label到复杂的table view、picker view、scroll view。当预定义的view不能满足你的需求的时候,你还能创建自定义view来管理view的绘制和事件处理。
view是UIView类(或其子类)的实例,它管理应用的window中的一块矩形区域。view负责绘制内容、处理事件、管理subview的布局。绘制内容涉及到使用Core Graphics、OpenGL ES或者UIKit来绘制形状、图片和文字。view同时还负责处理对其矩形区域内发生的触摸或者手势事件。在view的层级结构(hierarchy)中,parent view负责他们的child view的布局并且可以动态的随时调整布局,这在界面旋转或者实现界面动画的情况下尤其有用。
window是UIWindow类的实例并且用于处理应用总的界面呈现。一般来说应用的window基本不会变化:当一个window被创建后,它就待在那儿,只有window里的view会经常发生变化。基本上一个应用就一个window,如果设备接入了外部显示,那么应用会创建第二个window用于在外部显示上呈现内容。
动画用来为用户提供内容变化的视觉反馈。系统定义了在模态化view和不同view之间切换的标准动画。当然view的很多属性也可以使用动画效果,例如:view的透明度、位置、背景色等。如果你直接使用view底层的Core Animation Layer,你还能做出更多炫酷的动画效果。
Interface Builder是一个可视化编辑window和view的工具。使用IB,你的view都存放在一个nib(xib)文件中。你可以把nib文件想像成是存储view和其他对象的序列化资源文件。当你在运行时load一个nib文件的时候,里面的对象会重新组成到内存中并且可以被代码操作。
二、View和Window的结构
1. View结构基础
view和Core Animation Layer配合来处理view的绘制和动画效果。每个view的背后都有一个layer对象(通常是CALayer类的实例)负责这个view的绘制和动画效果。大多数情况下你只需要和UIView的接口打交道,只有在某些特定的情况下你才需要操作layer对象。
为了帮助理解view和layer之间的关系,可以参考图1-1。在图1-1中我们可以看到UIBarButtonItem是没有layer的,因为它是由UIToolbar绘制出来的,并非一个独立的view。
图1-12. View的层级结构和Subview管理
当一个view包含另一个view的时候,两个view之间就有了parent-child关系。child view就叫subview,parent view就叫superview。
视觉上,subview的内容遮盖superview全部或部分的内容空间。如果subview是不透明的,那他就彻底遮盖了superview对应的部分。如果subview是部分透明的,那这两个view的内容就会混合在一起显示(想象成高斯模糊的那种效果)。每个superview将它的subview存储在一个排序过的数组里。越晚添加的或者顺序越大的显示在越上面。
superview - subview的这种关系也会影响到一些view的行为。例如:改变superview的大小也会使subview的大小和位置发生改变。还包括改变superview的透明度、改变superview的坐标系统。
view的层级关系还影响到事件的传递。当某个view中发生了触摸事件,如果当前的这个view无法处理,事件会顺着view的层级向上传递。特定的view还会把事件传递给responder对象,例如一个view controller。如果事件最终传递到最顶级的application对象,通常这个事件就被丢弃了。
3. View的绘制周期
UIView使用按需绘制的模式来呈现内容。当一个view首次呈现在屏幕上时,系统会要求它绘制一下它的内容。然后系统会捕捉一张快照,并且一直使用它。如果你不改变view的内容,那么view的绘制代码就不会被再次执行。当你改变了view的显示内容,你应该使用view的setNeedsDisplay或setNeedsDisplayInRect方法来要求重绘。如果你是自定义UIView的子类,那么通常你应该重载drawRect方法来绘制你的view。你也有其他方法来绘制view,例如直接在layer上绘制,但通常你应该重载drawRect来实现自定义view的绘制。
4. View的Content Mode
每个view有一个content mode,当view的几何形状发生变化时,它用来控制view的内容是否需要重绘或者将如何改变。
当你进行如下操作时,content mode将会起作用:
- 改变view的frame或者bounds的宽高
- view的transform属性含有scale factor
默认的content mode是UIViewContentModeScaleToFill。它会使view的内容缩放以适应新的frame尺寸。图1-2显示了各种content mode下的内容缩放情况。
图1-2content mode有助于避免不必要的内容重绘,当然你也可以设置content mode为UIViewContentModeRedraw来强制view在每次缩放或尺寸改变时重绘(调用drawRect方法),但是通常你应当避免这么做。
5. 可拉伸的View
你可以指定view的某块区域为可拉伸,这样当view的尺寸改变的时候,只有可拉伸的区域会受到影响。一般会在按钮上使用这种技术。图1-3显示了可拉伸时,view是如何变化的。
图1-3使用view的content stretch属性来指定可拉伸的区域。这个属性接受一个rectangle值来表示可拉伸区域,并且这个值会归一化到0.0 - 1.0。这样当拉伸发生时,系统可以用view的当前bounds以及scale factor乘以这个归一化的值来决定如何缩放。另外view的content mode也会影响拉伸。只有UIViewContentModeScaleToFill、UIVieweContentModeScaleAspectFit和UIViewContentModeScaleAspectFill这几个content mode才会出发拉伸。
推荐在设置view的背景时使用一个可拉伸的UIImage对象来实现拉伸
6. 内置动画支持
UIView类的一些属性是支持半自动动画的。你只需要:
- 告诉UIKit你要使用动画了!
- 改变这些属性的值
这些属性有:
- frame —— 位置和尺寸的动画
- bounds —— 尺寸动画
- center —— 位置动画
- transform —— 旋转和缩放动画
- alpha —— 改变透明度
- backgroundColor —— 改变背景色
- cententStretch —— 改变view如何拉伸
一般来说,viewcontroller之间过度时会使用动画。当然你也可以直接在两个view之间使用动画。另外,除了使用UIKit类来实现动画,你还能使用Core Animation Layer来实现动画,它能提供更多的时间和属性上的控制。
下篇 View编程指南(二)
网友评论