在开始前,我想大家应该先读一读 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挺重要,所以接下来的文章里会有对这个方法的详细讲解。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述