在开始前,我想大家应该先读一读 Mac OS X 背后的故事,是一篇非常不错的文章。了解曾经发生的过去,才能对现在为什么会是这样有更深刻的认识。
xib与nib的渊源
Project Builder 在 Mac OS X 10.3 时被重命名为现在大家所熟知的 Xcode。Xcode 3以前,Interface Builder 使用一种名为 nib 格式的二进制文件格式。不过由于 nib 不能用肉眼读,也不方便使用版本管理工具来管理,所以 Xcode 3 开始新加入一种名为 xib 的文本文件格式,最后再在项目编译阶段输出为 nib 格式。和产生静态界面布局代码的工具很不同,nib 是不被转译成相应 Objective-C 代码的。用户程序执行时,nib 文件被读入,解包,所以 nib 文件是在运行时动态加载的。
UIView类代表的含义
UIView继承于UIResponder类,因此它主要表达了两个意思
1.可视(CALayer)
2.可互交(UIResponder)
每个UIView都有一个隐式层(implicit Layer),View本身就是这个隐式层的Delegate.
为什么要有层这个东西?因为作图等都是在层上完成,然后再合成。因为UIView有了Layer所以才能显示。
Layer又有两部分组成。present layer和Model layer.
present layer表示了中间的过程状态,而Model layer则表示了起始和结束状态
初始化方法
- (id)initWithFrame:(CGRect)frame
其中frame指定了这个View的大小和位置,起始点在左上角。
UIView的子类
一、UIWindow
UIWindow是作为包含了其他所有View的一个容器。每一个程序里面都会有一个UIWindow。下面这段代码里我们在程序启动完成后实例化了一个UIWindow类,并调用了它的makeKeyAndVisible方法。这个方法使得window在屏幕上可见。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible]; return YES; }
让View显示在屏幕上
一旦window在屏幕上可见了,之后任何加入window的view都会在屏幕上可见。换句话说,要使得一个view在屏幕上可见,需要把它加入到window之中。
这种层级关系可以直接调用UIView类的addSubview方法来实现,比如
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; MyView *view = [[MyView alloc] initWithFrame:viewFrame]; [[self window] addSubview:view]; [self.window makeKeyAndVisible];
return YES; }
也可以通过界面编辑器(Interface Builder)生成xib文件,然后我们通过UIViewController加载这个xib来实现。这就是MVC模式中C和V的关系,Controller通过连线的方式持有View的引用。当然直接通过实例化的方式持有,完全不使用Interface Builder也是可以的。
我们在项目中会有一个叫MyViewController以.xib作为扩展名的文件,我们之所以用这种结合了Interface Builder的方式去初始化一个Controller,是为了让这个Controller能方便的响应它所持有的View的所触发的事件。下节讲UITableView的时候会详细讲解。
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle { self = [super initWithNibName:@"MyViewController" bundle:appBundle]; return self;
}
然后把这个controller作为window的rootViewController, 就可以显示了。框架会自动把UIViewController所持有的View加入到window的subviews里。
drawRect方法,决定了View长啥样
默认情况下,draRect: 方法啥都不做,交给UIView的子类去实现这个方法,让子类有不同的样子。例如,UIButton的drawRect:方法可以绘制一个圆角的四方形,并在正中显示标题字符串。当你覆盖drawRect方法的时候,系统会为View准备一个graphics context, 接着系统会激活这个context,然后调用需要绘图的UIView对象的drawRect方法。我们可以通过UIGraphicsGetCurrentContext方法来获取已经激活的context, 这个context的类型就是CGContextRef,它负责合并然后生成一个image。这个image就是View最终的样子。
- (void)drawRect:(CGRect)dirtyRect { CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds]; center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0; float maxRadius = hypot(bounds.size.width, bounds.size.height) / 4.0; CGContextStrokePath(ctx); }
我们在子类覆盖了这个方法以后,初始化这个子类就能得到下图
因为drawRect挺重要,所以接下来的文章里会有对这个方法的详细讲解。