使用XIB开发界面

首先声明,我这是根据别人的讲解来写出来的,,,

一、关于xib

1.xib和nib

在程序里面我们看到的基本上是UINib这个类。xib文件可以可以被Xcode编译成为nib文件、xib文件其实就是一个xml文件,而nib文件就是编译后的二进制文件。

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加载进来的View大小是确定的,但是该视图在父视图中的位置是不确定的

// 此外,视图中的子视图也是原封不动地Load进来的

CGRect rect = _cell1.frame;

rect.origin.x += 50.0f;

rect.origin.y += 50.0f;

_cell1.frame = rect;

[self.view addSubview:_cell1];

}

运行结果:

结论:  

    1).File’s Owner为nil的xib文件中的视图属于通用视图,在工程中可以复用

    2).从xib加载进来的View大小是确定的,但是该视图在父视图中的位置是不确定的,因此需要开发者自行指定

    3).视图中的所有子视图会被原封不动地Load进来

2. 加载xib中File’s Owner为self的视图

cell2.xib

viewCaontroller.m

.......

@property (strong, nonatomic) IBOutlet UIView *cell2;

.......

- (void)loadCell2{

// cell2.xib的File's Owner设为self,并建立了一个从该xib的View到self的IBOutlet cell2

[[NSBundle mainBundle] loadNibNamed:@"cell2" owner:self options:nil];

// 只要self主动调用Load XIB的方法,self持有的IBOutlet指向的视图就会被初始化

// 这里不需要通过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];

}

运行结果:

结论:

      1).File’s Owner不为nil的xib文件中的视图属于专用视图,在工程中不应该被复用

      2).只要self主动调用loadNibNamed:owner:options:方法,self持有的IBOutlet指向的视图就会被初始化

      3).存取xib中的视图不用views[0]的方式,而是通过IBOutlet类型的property进行存取

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类的实例,并建立了一个从该xib的View到Cell3实例的IBOutlet

// 只要通过_cell3主动调用Load XIB的方法,该IBOutlet指向的视图就会被初始化

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];

}

运行结果:

结论:

      1).File’s Owner类可以封装视图中的各种逻辑,而不仅仅是提供视图内容

      2).只要通过File’s Owner类主动调用loadNibNamed:owner:options:方法,该IBOutlet指向的视图就会被初始化

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文件名和本类类名必须一致

// 这个xib文件的File's Owner必须为空

// 这个xib文件必须只拥有一个视图,并且该视图的class为本类

NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];

return views[0];

}

- (void)awakeFromNib {

// 视图内容布局

self.backgroundColor = [UIColor yellowColor];

self.titleLabel.textColor = [UIColor whiteColor];

}

运行结果:


结论:

这里的viewFromNib方法只是对loadNibNamed:owner:options:方法的一个简单封装,要求的条件包括: -xib文件名和本类类名必须一致 - 这个xib文件的File’s Owner必须为空 -这个xib文件必须只拥有一个视图,并且该视图的class为本类

5. 通过UIViewController的initWithNibName:bundle:方法加载xib文件中的视图

cell5.xib

如果Cell5ViewController类希望self.view就是xib文件中的View,可以在Connections页中建立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];

}

运行结果:

结论:

将xib的File’s Owner设成一个UIViewController子类,可以将这个xib文件的视图展示和外部响应事件(例如点击一个按钮触发的点击事件,该视图的手势事件等)全部封装在一个ViewController中,如果把按钮的点击事件封装在一个UIView类中,貌似破坏了MVC模式,因此最好将xib的File’s Owner设成一个UIViewController子类,该类可以通过 addChildViewController方法将其添加到现有的ViewController上。如果只是希望加载视图,可以通过viewcontroller.view存取。

如果希望ViewControllerA加载并响应aXIBView中的按钮点击事件,这时必须建立一个aXIBView到ViewControllerA的IBAction,如果ViewControllerA需要拥有多个这样的XIB,那么ViewControllerA会变得非常的庞大,此时可以通过为每一个XIB设置一个ViewController,再让ViewControllerA加载这些Child ViewControllers,这样可以将这些事件的响应职责和视图的描绘工作分派给专门的Child ViewController,在减小ViewControllerA体积的同时,也可以提高各个xib的可复用性。

    这里的viewControllerFromNIB方法其实就是initWithNibName:bundle:方法的一个简单封装,要求:xib的File’s Owner设为本类。

6. 通过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]会由调用的类决定

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文件中的视图和其按钮响应事件全部封装在Cell6ViewController

// 如果Cell6ViewController的按钮响应事件由ViewController作出响应,那么二者的耦合度就过高

// 建议:

// 单纯的通用View展示,使用从xib文件加载视图的方法,File's Owner设为nil

// 特定拥有者的View展示,从xib文件加载视图时,File's Owner设为拥有者

// 如果视图中有按钮响应事件,或其它可以和用户交互的事件,建议采用从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];

}

运行结果:

结论:

这里我专门写了一个UIViewController+NIB的category,只需要调用loadFromNib类方法就可以加载xib中的视图。(我的示例中的xib的名字和控制器的名字是不一样的,你可以弄成一样的,让后使用NSStringFromClass(controllerClass)来通用加载就可以了)要求: - xib文件的File’s Owner必须设置为对应的View Controller类。

三、总结

在写界面时同时混用xib和代码可以提高效率,而对xib的使用主要体现在其专用性和通用性上。

注意:在xib中可以有多个视图控件,但是从xib中load出来的是一个数组,那么怎么来确定哪个对象对应的是哪个控件呢?

。。。。。。。。结论。。。。。。。。。。。

从xib中load出来的views数组中视图对象的排列顺序和xib 左边的对象排列顺序一致(其实就是xml文件中元素的排序而已),在下图的位置。。。。。)(虽然我只有一个对象,,,当然我的目的是告诉大家是在那个地方!!!!)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容