在项目中有些 view 需要独立做成一个组件,供多个 VC 使用,而且本人项目中习惯使用 XIB,所以这个 view 的组件也希望使用 XIB 来实现。但是当我们创建 UIView 的时候默认是不包含 XIB 文件的,这就需要再创建一个同名的 XIB 文件。但是如何把 XIB 和 UIview 关联起来呢。
通常我们通过代码加载 XIB 的方法是:
+(id)viewFromNibNamed:(NSString*)nibName owner:(id)owner{ NSArray* nibView = [[NSBundle mainBundle] loadNibNamed:nibName owner:owner options:nil]; return [nibView firstObject]; } |
---|
注意到上面有一个 owner 属相,这个属性就是表明这个 view 文件的所有者,通常对应一个 VC。
单纯的创建 view 类和同名的 XIB 是没有效果的,接下来要做的就是把 XIB 和对应的 view 类关联起来
关联有两种方式,假设自定义的的UIView子类为TestView,三个文件分别为:TestView.h
,TestView.m
,TestView.xib
XIB 中的 UIView 控件与类关联
这种方式就是设置 XIB 中 view 的 custom class 为TestView。
使用方式为
NSArray* nibView = [[NSBundle mainBundle] loadNibNamed:@"TestView" owner:nil options:nil]; TestView *testView = [nibView firstObject]; [self.view addSubview:testView]; |
---|
这种方式会通过initWithCoder:
方法来从 XIB 文件初始化该 view。使用的时候我们可以通过awakeFromNib
方法来做进一步处理。
通过这种方式需要注意的是在initWithCoder:
方法中,并没有建立 XIB 和 TestView 的 IBOutlet 连接,所以在这里通过代码引用 XIB 中的控件是引用不到的,而当awakeFromNib
执行的时候,各种 IBOutlet 都连接好了。所以如果有子控件的初始化工作,最好放在awakeFromNib
里面。
通过 File’s owner 来关联
这种方式是设置 XIB 中的 File’s owner 为TestView。
这种方式创建 view 需要手动来初始化
- (instancetype)initFromNibWithFrame:(CGRect)frame owner:(id)owner{ owner = owner ?: self; UIView *nibView = [UIView viewFromNibNamed:NSStringFromClass([self class]) owner:owner]; if (!nibView) returnnil; nibView.frame = frame; self = [super initWithFrame:nibView.frame]; [self addSubview:nibView]; [self nib_viewDidLoad]; returnself; } |
---|
初始化可以在自定义的nib_viewDidLoad
里面进行,这个时候 XIB 和 TestView 的 IBOutlet 连接也已经建立好了
由于XIB没有设置 view 的 custom class 所以并不会执行initWithCoder:
和awakeFromNib
方法。
缺点
上面两种方式都可以实现通过代码加载 XIB 的目的。
但是有一种情况就是我们的 viewController 也使用 XIB 来布局的,这个时候如果我们拖拽一个 view 在 VC 的 XIB 中,然后设置这个 View 的 custom class 为 TestView 时,上面的方法就无效了。因为虽然同样是 TestView ,但是加载布局文件不同,这里所加载的布局文件是 VC 所在 XIB 的布局文件。
另外,XIB 中的 file’s owner 其实也就类似是传统 MVC 中的 controller 的角色,因此其最好是 UIVIew,NSObject,UIViewController 这样的类。
参考
如何设计一个 iOS 控件?(iOS 控件完全解析)
-loadNibNamed:owner:options:的深入研究
ios 开发file’s owner以及outlet与连线的理解
对xib/nib, file’s owner, first responder的理解