首先聲明壳猜,我這是根據(jù)別人的講解來(lái)寫(xiě)出來(lái)的虹曙,,绒障,
一吨凑、關(guān)于xib
1.xib和nib
在程序里面我們看到的基本上是UINib這個(gè)類。xib文件可以可以被Xcode編譯成為nib文件户辱、xib文件其實(shí)就是一個(gè)xml文件鸵钝,而nib文件就是編譯后的二進(jìn)制文件。
2.Xib文件的重要屬性
1.xib文件名
2.File’s Owner
3.xib文件中的視圖的Class
4.xib文件中的視圖的Outlet指向
二 庐镐、Demo演示
demo演示:GitHub - liubitao/test: test?
1.加載歐xib中File’s Owner為nil的視圖
cell1.xib
ViewController.m
- (void)loadCell1{
// cell.xib的File's Owner為nil
NSArray *views = [[NSBundle mainBundle]loadNibNamed:@"cell1" owner:nil options:nil];
self.cell1 = [views lastObject];
// 從xib加載進(jìn)來(lái)的View大小是確定的恩商,但是該視圖在父視圖中的位置是不確定的
// 此外,視圖中的子視圖也是原封不動(dòng)地Load進(jìn)來(lái)的
CGRect rect = _cell1.frame;
rect.origin.x += 50.0f;
rect.origin.y += 50.0f;
_cell1.frame = rect;
[self.view addSubview:_cell1];
}
運(yùn)行結(jié)果:
結(jié)論: ?
??? 1).File’s Owner為nil的xib文件中的視圖屬于通用視圖必逆,在工程中可以復(fù)用
??? 2).從xib加載進(jìn)來(lái)的View大小是確定的怠堪,但是該視圖在父視圖中的位置是不確定的,因此需要開(kāi)發(fā)者自行指定
??? 3).視圖中的所有子視圖會(huì)被原封不動(dòng)地Load進(jìn)來(lái)
2. 加載xib中File’s Owner為self的視圖
cell2.xib
viewCaontroller.m
.......
@property (strong, nonatomic) IBOutlet UIView *cell2;
.......
- (void)loadCell2{
// cell2.xib的File's Owner設(shè)為self名眉,并建立了一個(gè)從該xib的View到self的IBOutlet cell2
[[NSBundle mainBundle] loadNibNamed:@"cell2" owner:self options:nil];
// 只要self主動(dòng)調(diào)用Load XIB的方法粟矿,self持有的IBOutlet指向的視圖就會(huì)被初始化
// 這里不需要通過(guò)views[0]的方式存取視圖
CGRect rect = _cell2.frame;
rect.origin.x = _cell1.frame.origin.x;
rect.origin.y = _cell1.frame.origin.y + 80.0f;
_cell2.frame = rect;
[self.view addSubview:_cell2];
}
運(yùn)行結(jié)果:
結(jié)論:
????? 1).File’s Owner不為nil的xib文件中的視圖屬于專用視圖,在工程中不應(yīng)該被復(fù)用
????? 2).只要self主動(dòng)調(diào)用loadNibNamed:owner:options:方法损拢,self持有的IBOutlet指向的視圖就會(huì)被初始化
????? 3).存取xib中的視圖不用views[0]的方式陌粹,而是通過(guò)IBOutlet類型的property進(jìn)行存取
3. 加載xib中File’s Owner為特定類的視圖
cell3.xib
Cell3View.h
@interface Cell3View : UIView
@property (strong, nonatomic) IBOutlet UIView *cellView3;
@end
ViewController.m
...
@property (nonatomic,strong) Cell3View *cell3;
...
- (void)loadCell3{
// cell3.xib的File's Owner是Cell3類的實(shí)例,并建立了一個(gè)從該xib的View到Cell3實(shí)例的IBOutlet
// 只要通過(guò)_cell3主動(dòng)調(diào)用Load XIB的方法福压,該IBOutlet指向的視圖就會(huì)被初始化
self.cell3 = [[Cell3View alloc]init];
[[NSBundle mainBundle] loadNibNamed:@"cell3" owner:_cell3 options:nil];
UIView *view = _cell3.cellView3;
CGRect rect = view.frame;
rect.origin.x = _cell1.frame.origin.x;
rect.origin.y = _cell2.frame.origin.y + 80.0f;
view.frame = rect;
[self.view addSubview:view];
}
運(yùn)行結(jié)果:
結(jié)論:
????? 1).File’s Owner類可以封裝視圖中的各種邏輯掏秩,而不僅僅是提供視圖內(nèi)容
????? 2).只要通過(guò)File’s Owner類主動(dòng)調(diào)用loadNibNamed:owner:options:方法,該IBOutlet指向的視圖就會(huì)被初始化
4. 加載xib中文件名和視圖類名一致的視圖(File’s Owner為nil)
Cell4.xib
Cell4.h
@interface Cell4 : UIView
+ (instancetype)viewFromNIB;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@end
Cell4.m
+ (instancetype)viewFromNIB {
// 加載xib中的視圖荆姆,其中xib文件名和本類類名必須一致
// 這個(gè)xib文件的File's Owner必須為空
// 這個(gè)xib文件必須只擁有一個(gè)視圖蒙幻,并且該視圖的class為本類
NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
return views[0];
}
- (void)awakeFromNib {
// 視圖內(nèi)容布局
self.backgroundColor = [UIColor yellowColor];
self.titleLabel.textColor = [UIColor whiteColor];
}
運(yùn)行結(jié)果:
結(jié)論:
這里的viewFromNib方法只是對(duì)loadNibNamed:owner:options:方法的一個(gè)簡(jiǎn)單封裝,要求的條件包括: -xib文件名和本類類名必須一致 - 這個(gè)xib文件的File’s Owner必須為空 -這個(gè)xib文件必須只擁有一個(gè)視圖胆筒,并且該視圖的class為本類
5. 通過(guò)UIViewController的initWithNibName:bundle:方法加載xib文件中的視圖
cell5.xib
如果Cell5ViewController類希望self.view就是xib文件中的View邮破,可以在Connections頁(yè)中建立view -> File’s Owner的Outlet,如下:
Cell5ViewController.h/m
@interface Cell5ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@end
@implementation Cell5ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.titleLabel.textColor = [UIColor whiteColor];
}
ViewController.m
...
@property (nonatomic,strong) Cell5ViewController *cell5VC;
...
- (void)loadCell5{
//加載控制器
self.cell5VC = [[Cell5ViewController alloc] initWithNibName:@"cell5" bundle:[NSBundle mainBundle]];
UIView *cell5 = _cell5VC.view;
CGRect rect = cell5.frame;
rect.origin.x = _cell4.frame.origin.x;
rect.origin.y = _cell4.frame.origin.y + 80.0f;
cell5.frame = rect;
[self.view addSubview:cell5];
}
運(yùn)行結(jié)果:
結(jié)論:
將xib的File’s Owner設(shè)成一個(gè)UIViewController子類腐泻,可以將這個(gè)xib文件的視圖展示和外部響應(yīng)事件(例如點(diǎn)擊一個(gè)按鈕觸發(fā)的點(diǎn)擊事件决乎,該視圖的手勢(shì)事件等)全部封裝在一個(gè)ViewController中队询,如果把按鈕的點(diǎn)擊事件封裝在一個(gè)UIView類中派桩,貌似破壞了MVC模式,因此最好將xib的File’s Owner設(shè)成一個(gè)UIViewController子類蚌斩,該類可以通過(guò) addChildViewController方法將其添加到現(xiàn)有的ViewController上铆惑。如果只是希望加載視圖,可以通過(guò)viewcontroller.view存取。
如果希望ViewControllerA加載并響應(yīng)aXIBView中的按鈕點(diǎn)擊事件员魏,這時(shí)必須建立一個(gè)aXIBView到ViewControllerA的IBAction丑蛤,如果ViewControllerA需要擁有多個(gè)這樣的XIB,那么ViewControllerA會(huì)變得非常的龐大撕阎,此時(shí)可以通過(guò)為每一個(gè)XIB設(shè)置一個(gè)ViewController受裹,再讓ViewControllerA加載這些Child ViewControllers,這樣可以將這些事件的響應(yīng)職責(zé)和視圖的描繪工作分派給專門(mén)的Child ViewController虏束,在減小ViewControllerA體積的同時(shí)棉饶,也可以提高各個(gè)xib的可復(fù)用性。
??? 這里的viewControllerFromNIB方法其實(shí)就是initWithNibName:bundle:方法的一個(gè)簡(jiǎn)單封裝镇匀,要求:xib的File’s Owner設(shè)為本類照藻。
6. 通過(guò)UIViewController+NIB加載xib文件中的View Controller類和其視圖
cell6.xib
UIViewController+NIB.h/m
@interface UIViewController (NIB)
//?要求xib文件名和View?Controller類名一致
+?(instancetype)loadFromNib;
@end
@implementation?UIViewController?(NIB)
+ (instancetype)loadFromNib {
// [self class]會(huì)由調(diào)用的類決定
Class controllerClass = [self class];
NSLog(@"class = %@", controllerClass);
return [[controllerClass alloc] initWithNibName:@"cell6" bundle:[NSBundle mainBundle]];
}
@end
Cell6ViewController.h/m
@interface Cell6ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *action;
@end
@implementation Cell6ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
self.titleLabel.text = @"Gray View";
self.titleLabel.textColor = [UIColor whiteColor];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.font = [UIFont systemFontOfSize:8.5f];
[self.action setTitle:@"action" forState:UIControlStateNormal];
[self.action setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
// 推薦從XIB文件中加載View Controller的方法,這種方法可以將XIB文件中的視圖和其按鈕響應(yīng)事件全部封裝在Cell6ViewController
// 如果Cell6ViewController的按鈕響應(yīng)事件由ViewController作出響應(yīng)汗侵,那么二者的耦合度就過(guò)高
// 建議:
// 單純的通用View展示幸缕,使用從xib文件加載視圖的方法,F(xiàn)ile's Owner設(shè)為nil
// 特定擁有者的View展示晰韵,從xib文件加載視圖時(shí)发乔,F(xiàn)ile's Owner設(shè)為擁有者
// 如果視圖中有按鈕響應(yīng)事件,或其它可以和用戶交互的事件雪猪,建議采用從XIB文件中加載View Controller的方法列疗,這樣可以封裝UI展示和交互事件
- (IBAction)action:(id)sender{
NSLog(@"action");
}
ViewController.m
...
@property (nonatomic,strong) Cell6ViewController *cell6VC;
...
- (void)loadCell6{
self.cell6VC = [Cell6ViewController loadFromNib];
UIView *cell6 = _cell6VC.view;
UIView *cell5 = _cell5VC.view;
CGRect rect = cell6.frame;
rect.origin.x = cell5.frame.origin.x;
rect.origin.y = cell5.frame.origin.y + 80.0f;
cell6.frame = rect;
[self.view addSubview:cell6];
}
運(yùn)行結(jié)果:
結(jié)論:
這里我專門(mén)寫(xiě)了一個(gè)UIViewController+NIB的category,只需要調(diào)用loadFromNib類方法就可以加載xib中的視圖浪蹂。(我的示例中的xib的名字和控制器的名字是不一樣的抵栈,你可以弄成一樣的,讓后使用NSStringFromClass(controllerClass)來(lái)通用加載就可以了)要求: - xib文件的File’s Owner必須設(shè)置為對(duì)應(yīng)的View Controller類坤次。
三古劲、總結(jié)
在寫(xiě)界面時(shí)同時(shí)混用xib和代碼可以提高效率,而對(duì)xib的使用主要體現(xiàn)在其專用性和通用性上缰猴。
注意:在xib中可以有多個(gè)視圖控件产艾,但是從xib中l(wèi)oad出來(lái)的是一個(gè)數(shù)組,那么怎么來(lái)確定哪個(gè)對(duì)象對(duì)應(yīng)的是哪個(gè)控件呢滑绒?
闷堡。。疑故。杠览。。纵势。踱阿。管钳。結(jié)論。软舌。才漆。。佛点。醇滥。。超营。腺办。。糟描。
從xib中l(wèi)oad出來(lái)的views數(shù)組中視圖對(duì)象的排列順序和xib 左邊的對(duì)象排列順序一致(其實(shí)就是xml文件中元素的排序而已)怀喉,在下圖的位置。船响。躬拢。。见间。)(雖然我只有一個(gè)對(duì)象聊闯,,米诉,當(dāng)然我的目的是告訴大家是在那個(gè)地方A馐摺!J仿隆K┟凇)