iOS - Xib
前言
xib 文件可以被 Xcode 编译成 nib 文件,xib 文件本质上是一个 xml 文件,而 nib 文件就是编译后的二进制文件,该文件将视图等控件对象封装了起来,而在程序运行起来后,这些对象会被激活。xib 可以用 vim 或 cat 命令查看。nib 文件可以在程序的 Build 目录下找到。
xib 文件有以下几个重要的属性,从哪里加载 xib,加载 xib 中的什么视图,都可以根据这几个属性得出。
- xib 文件名
- File’s Owner
- xib 文件中的视图的 Class
- xib 文件中的视图的 Outlet 指向
在写界面时同时混用 xib 和代码可以提高效率,而对 xib 的使用主要体现在其专用性和通用性上。
对于一些专门的界面,例如 App 中的设置界面,纯代码写难免会浪费时间,此时可以通过 xib 文件的拖控件方法来定制。这个 xib 是专用于某一个界面的,目的是提高效率。
对于一些通用的控件甚至界面,例如一个很漂亮但实现起来非常复杂的按钮,此时可以通过 load xib 文件中的视图来快速添加。这个 xib 对于所有视图是共用的,目的是提高可复用性。
对于通用的 xib:
- 如果 xib 只是单纯的界面展示,那么 File’s Owner 可以随意。
- 如果 xib 中包含了按钮、手势等用户输入事件,那么 File’s Owner 最好设置为 UIViewController 类的子类。
xib 中可以有多个视图控件,从 xib 中 load 出来的 views 数组中视图对象的排列顺序和 xib scene 中的对象排列顺序一致(其实就是 xml 文件中元素的排序而已)。
1、xib 文件加载
1)xib 文件加载方式
1> 方法 1
// Test 为 xib 文件名
NSArray *objs = [[NSBundle mainBundle] loadNibNamed:@"Test" owner:nil options:nil]; [self.view addSubview:objs[1]];
2> 方法 2
// 一个 UINib 对象就代表一个 xib 文件
/*
一般情况下,bundle 参数传 nil,默认就是 mainBundle
*/
UINib *nib = [UINib nibWithNibName:@"Test" bundle:[NSBundle mainBundle]]; NSArray *objs = [nib instantiateWithOwner:nil options:nil];
[self.view addSubview:objs[1]];
2)使用 xib 自定义 view 的步骤
新建自定义控件类
新建 xib 文件(文件名建议和自定义控件类的类名一致)
修改 xib 中控件绑定的类名
在类扩展中增加子控件的属性,关联 xib 中的子控件。封装 xib 的加载过程,增加模型属性,在模型属性 setter 方法中设置数据到子控件上。
1.1 加载 xib 中 File’s Owner 为 nil 的视图
Objective-C
BlueView.xib
- 由于 BlueView 会放到其它 View 上作为 subview,所以这儿 size 是 Freeform, Status Bar 是 None。
MainViewController.m
@property (strong, nonatomic) UIView *blueView; - (void)loadBlueViewFromXIB { // BlueView.xib 的 File's Owner 为 nil NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"BlueView" owner:nil options:nil]; _blueView = views[0];
[self.view addSubview:_blueView]; // 从 xib 加载进来的 View 大小是确定的,但是该视图在父视图中的位置是不确定的。此外,视图中的子视图也是原封不动地 Load 进来的 CGRect frame = _blueView.frame;
frame.origin.x += 50.0f;
frame.origin.y += 80.0f;
_blueView.frame = frame;
}
Swift
BlueView.xib
同 Objective-C 设置
MainViewController.swift
var blueView:UIView! func loadBlueViewFromXIB() { // BlueView.xib 的 File's Owner 为 nil let views = NSBundle.mainBundle().loadNibNamed("BlueView", owner: nil, options: nil) blueView = views[0] as! UIView
self.view.addSubview(blueView) // 从 xib 加载进来的 View 大小是确定的,但是该视图在父视图中的位置是不确定的。此外,视图中的子视图也是原封不动地 Load 进来的 var frame = blueView.frame
frame.origin.x += 50.0
frame.origin.y += 80.0
blueView.frame = frame
}
结论:
- File’s Owner 为 nil 的 xib 文件中的视图属于通用视图,在工程中可以复用。
- 从 xib 加载进来的 View 大小是确定的,但是该视图在父视图中的位置是不确定的,因此需要开发者自行指定。
- 视图中的所有子视图会被原封不动地 Load 进来。
1.2 加载 xib 中 File’s Owner 为 self 的视图
Objective-C
GreenView.xib
MainViewController.m
@property (strong, nonatomic) IBOutlet UIView *greenView; - (void)loadGreenViewFromXIB { // GreenView.xib 的 File's Owner 设为 self,并建立了一个从该 xib 的 View 到 self 的 IBOutlet greenView [[NSBundle mainBundle] loadNibNamed:@"GreenView" owner:self options:nil]; [self.view addSubview:_greenView]; // 只要 self 主动调用 Load XIB 的方法,self 持有的 IBOutlet 指向的视图就会被初始化。这里不需要通过 views[0] 的方式存取视图 CGRect frame = _greenView.frame;
frame.origin.x = _blueView.frame.origin.x;
frame.origin.y = _blueView.frame.origin.y + 80.0f;
_greenView.frame = frame;
}
Swift
GreenView.xib
同 Objective-C 设置
MainViewController.swift
@IBOutlet var greenView: UIView! func loadGreenViewFromXIB() { // GreenView.xib 的 File's Owner 设为 self,并建立了一个从该 xib 的 View 到 self 的 IBOutlet greenView NSBundle.mainBundle().loadNibNamed("GreenView", owner: self, options: nil) self.view.addSubview(greenView) // 只要 self 主动调用 Load XIB 的方法,self 持有的 IBOutlet 指向的视图就会被初始化。这里不需要通过 views[0] 的方式存取视图 var frame = greenView.frame
frame.origin.x = blueView.frame.origin.x
frame.origin.y = blueView.frame.origin.y + 80.0
greenView.frame = frame
}
结论:
- File’s Owner 不为 nil 的 xib 文件中的视图属于专用视图,在工程中不应该被复用。
- 只要 self 主动调用 loadNibNamed:owner:options: 方法,self 持有的 IBOutlet 指向的视图就会被初始化。
- 存取 xib 中的视图不用 views[0] 的方式,而是通过 IBOutlet 类型的 property 进行存取。
1.3 加载 xib 中 File’s Owner 为特定类的视图
Objective-C
RedView.xib
RedViewOwner.h
@property (strong, nonatomic) IBOutlet UIView *redView;
MainViewController.m
@property (strong, nonatomic) RedViewOwner *redViewOwner;
@property (strong, nonatomic) UIView *redView; - (void)loadRedViewFromXIB { // RedView.xib 的 File's Owner 是 RedViewOwner 类的实例,并建立了一个从该 xib 的 View 到 RedViewOwner 实例的 IBOutlet。
// 只要通过 _redViewOwner 主动调用 Load XIB 的方法,该 IBOutlet 指向的视图就会被初始化 _redViewOwner = [RedViewOwner new]; [[NSBundle mainBundle] loadNibNamed:@"RedView" owner:_redViewOwner options:nil]; _redView = _redViewOwner.redView;
[self.view addSubview:_redView]; CGRect frame = _redView.frame;
frame.origin.x = _greenView.frame.origin.x;
frame.origin.y = _greenView.frame.origin.y + 80.0f;
_redView.frame = frame;
}
Swift
RedView.xib
同 Objective-C 设置
RedViewOwner.swift
@IBOutlet var redView: UIView!
MainViewController.swift
var redViewOwner:RedViewOwner!
var redView:UIView! func loadRedViewFromXIB() { // RedView.xib 的 File's Owner 是 RedViewOwner 类的实例,并建立了一个从该 xib 的 View 到 RedViewOwner 实例的 IBOutlet。
// 只要通过 _redViewOwner 主动调用 Load XIB 的方法,该 IBOutlet 指向的视图就会被初始化 redViewOwner = RedViewOwner() NSBundle.mainBundle().loadNibNamed("RedView", owner: redViewOwner, options: nil) redView = redViewOwner.redView
self.view.addSubview(redView) var frame = redView.frame
frame.origin.x = greenView.frame.origin.x
frame.origin.y = greenView.frame.origin.y + 80.0
redView.frame = frame
}
结论:
- File’s Owner 类可以封装视图中的各种逻辑,而不仅仅是提供视图内容。
- 只要通过 File’s Owner 类主动调用 loadNibNamed:owner:options: 方法,该 IBOutlet 指向的视图就会被初始化。
1.4 加载 xib 中文件名和视图类名一致的视图(File’s Owner 为 nil)
Objective-C
YellowView.xib
File’s Owner 为 nil
YellowView.h
// Convenience Method
+ (instancetype)viewFromNIB;
YellowView.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 就是 xib 文件中的 View
self.backgroundColor = [UIColor yellowColor];
}
MainViewController.m
@property (strong, nonatomic) YellowView *yellowView; - (void)loadYellowViewFromXIB { // 说明见 YellowView.m 的 viewFromNIB 方法 _yellowView = [YellowView viewFromNIB]; [self.view addSubview:_yellowView]; CGRect frame = _yellowView.frame;
frame.origin.x = _redView.frame.origin.x;
frame.origin.y = _redView.frame.origin.y + 80.0f;
_yellowView.frame = frame;
}
Swift
YellowView.xib
同 Objective-C 设置
YellowView.swift
class func viewFromNIB() -> AnyObject { // 加载 xib 中的视图,其中 xib 文件名和本类类名必须一致
// 这个 xib 文件的 File's Owner 必须为空
// 这个 xib 文件必须只拥有一个视图,并且该视图的 class 为本类 let views = NSBundle.mainBundle().loadNibNamed("YellowView", owner: nil, options: nil) return views[0]
} override func awakeFromNib() { // self 就是 xib 文件中的 View
self.backgroundColor = UIColor.yellowColor()
}
MainViewController.swift
var yellowView:YellowView! func loadYellowViewFromXIB() { // 说明见 YellowView.m 的 viewFromNIB 方法 yellowView = YellowView.viewFromNIB() as! YellowView self.view.addSubview(yellowView) var frame = yellowView.frame
frame.origin.x = redView.frame.origin.x
frame.origin.y = redView.frame.origin.y + 80.0
yellowView.frame = frame
}
结论:
- 这里的 viewFromNib 方法只是对 loadNibNamed:owner:options: 方法的一个简单封装,要求的条件包括:
- xib 文件名和本类类名必须一致。
- 这个 xib 文件的 File’s Owner 必须为空。
- 这个 xib 文件必须只拥有一个视图,并且该视图的 class 为本类。
- 这里的 viewFromNib 方法只是对 loadNibNamed:owner:options: 方法的一个简单封装,要求的条件包括:
1.5 通过 UIViewController 的 initWithNibName:bundle: 方法加载 xib 文件中的视图
Objective-C
BlackViewController.xib
- 如果 BlackViewController 类希望 self.view 就是 xib 文件中的 View,可以在 Connections 页中建立 view -> File’s Owner 的 Outlet。由 File’s Owner 右键拖动到 view 上。
BlackViewController.h
// Conveniece Method
+ (instancetype)viewControllerFromNIB;
BlackViewController.m
+ (instancetype)viewControllerFromNIB { return [[BlackViewController alloc] initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
} - (void)viewDidLoad {
[super viewDidLoad]; // self.view 就是 xib 文件中的 View
self.view.backgroundColor = [UIColor blackColor];
}
MainViewController.m
@property (strong, nonatomic) BlackViewController *blackViewController;
@property (strong, nonatomic) UIView *blackView; - (void)loadBlackViewFromXIB { _blackViewController = [[BlackViewController alloc] initWithNibName:@"BlackViewController" bundle:[NSBundle mainBundle]]; // 或使用 Conveniece Method,但要求 xib 文件名和 View Controller 类名一致
_blackViewController = [BlackViewController viewControllerFromNIB]; _blackView = _blackViewController.view;
[self.view addSubview:_blackView]; CGRect frame = _blackView.frame;
frame.origin.x = _yellowView.frame.origin.x;
frame.origin.y = _yellowView.frame.origin.y + 80.0f;
_blackView.frame = frame;
}
Swift
BlackViewController.xib
同 Objective-C 设置
BlackViewController.swift
class func viewControllerFromNIB() -> AnyObject { return BlackViewController(nibName: "BlackViewController", bundle: NSBundle.mainBundle())
} override func viewDidLoad() {
super.viewDidLoad() self.view.backgroundColor = UIColor.blackColor()
}
MainViewController.swift
var blackViewController:BlackViewController!
var blackView:UIView! func loadBlackViewFromXIB() { blackViewController = BlackViewController(nibName: "BlackViewController", bundle: NSBundle.mainBundle()) // 或使用 Conveniece Method,但要求 xib 文件名和 View Controller 类名一致
blackViewController = BlackViewController.viewControllerFromNIB() as! BlackViewController blackView = blackViewController.view;
self.view.addSubview(blackView) var frame = blackView.frame
frame.origin.x = yellowView.frame.origin.x
frame.origin.y = yellowView.frame.origin.y + 80.0
blackView.frame = frame
}
结论:
将 xib 的 File’s Owner 设成一个 UIViewController 子类,可以将这个 xib 文件的视图展示和外部响应事件(例如点击一个按钮触发的点击事件,该视图的手势事件等)全部封装在一个 View Controller 中,如果把按钮的点击事件封装在一个 UIView 类中,貌似破坏了 MVC 模式,因此最好将 xib 的 File’s Owner 设成一个 UIViewController 子类,该类可以通过 addChildViewController 方法将其添加到现有的 View Controller 上。如果只是希望加载视图,可以通过 viewcontroller.view 存取。
如果希望 ViewControllerA 加载并响应 aXIBView 中的按钮点击事件,这时必须建立一个 aXIBView 到 ViewControllerA 的 IBAction,如果 ViewControllerA 需要拥有多个这样的 XIB,那么 ViewControllerA 会变得非常的庞大,此时可以通过为每一个 XIB 设置一个 ViewController,再让 ViewControllerA 加载这些 Child View Controllers,这样可以将这些事件的响应职责和视图的描绘工作分派给专门的 Child View Controller,在减小 ViewControllerA 体积的同时,也可以提高各个 xib 的可复用性。
这里的 viewControllerFromNIB 方法其实就是 initWithNibName:bundle: 方法的一个简单封装,要求:xib 的 File’s Owner 设为本类。
1.6 通过 UIViewController + NIB 加载 xib 文件中的 View Controller 类和其视图
Objective-C
GrayViewController.xib
UIViewController+NIB.h
@interface UIViewController (NIB) // 要求 xib 文件名和 View Controller 类名一致
+ (instancetype)loadFromNib; @end
UIViewController+NIB.m
@implementation UIViewController (NIB) + (instancetype)loadFromNib { // [self class] 会由调用的类决定
return [[[self class] alloc] initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
} @end
GrayViewController.h
@property (weak, nonatomic) IBOutlet UIButton *actionButton;
GrayViewController.m
- (void)viewDidLoad {
[super viewDidLoad]; self.view.backgroundColor = [UIColor grayColor];
} // 推荐从 xib 文件中加载 View Controller 的方法,这种方法可以将 xib 文件中的视图和其按钮响应事件全部封装在 GrayViewController
// 如果 GrayViewController 的按钮响应事件由 MainViewController 作出响应,那么二者的耦合度就过高
// 建议:
// 单纯的通用 View 展示,使用从 xib 文件加载视图的方法,File's Owner 设为 nil
// 特定拥有者的 View 展示,从 xib 文件加载视图时,File's Owner 设为拥有者
// 如果视图中有按钮响应事件,或其它可以和用户交互的事件,建议采用从 xib 文件中加载 View Controller 的方法,这样可以封装 UI 展示和交互事件 - (IBAction)action:(UIButton *)sender { NSLog(@"action");
}
MainViewController.m
@property (strong, nonatomic) GrayViewController *grayViewController;
@property (strong, nonatomic) UIView *grayView; - (void)loadGrayViewFromXIB { _grayViewController = [GrayViewController loadFromNib]; _grayView = _grayViewController.view;
[self.view addSubview:_grayView]; CGRect frame = _grayView.frame;
frame.origin.x = _blackView.frame.origin.x;
frame.origin.y = _blackView.frame.origin.y + 80.0f;
_grayView.frame = frame;
}
结论:
- 这里我专门写了一个 UIViewController+NIB 的 category,只需要调用 loadFromNib 类方法就可以加载 xib 中的视图。要求:
- xib 文件的 File’s Owner 必须设置为对应的 View Controller 类。
- 这里我专门写了一个 UIViewController+NIB 的 category,只需要调用 loadFromNib 类方法就可以加载 xib 中的视图。要求:
iOS - Xib的更多相关文章
- ios xib或storyBoard的那些小方法
今天看了一下xib里的一些小技巧,但是百度一搜的话,网上已经有人写过教程了,在这里我也就懒一下,不写那么详细了,就写一些如何百度的方法! 1."通过KVC修改占位文字的颜色" [t ...
- iOS xib View宽高不能改变
IOS - xib(Interface Builder,view) - can't change view size(view不能改变大小问题) 今天在试着swift语言写个demo,,当中遇到了这个 ...
- **IOS:xib文件解析(xib和storyboard的比较,一个轻量级一个重量级)
使用Xcode做iOS项目,经常会和Xib文件打交道,因为Xib文件直观的展现出运行时视图的外观,所以上手非常容易,使用也很方便,但对于从未用纯代码写过视图的童鞋,多数对Xib的理解有些片面. Xib ...
- IOS xib和代码自定义UIView
https://www.jianshu.com/p/1bcc29653085 总结的比较好 iOS开发中,我们常常将一块View封装起来,以便于统一管理内部的子控件. 下面就来说说自定义View的封装 ...
- iOS - xib中关于拖拽手势的潜在错误
iOS开发拓展篇—xib中关于拖拽手势的潜在错误 一.错误说明 自定义一个用来封装工具条的类 搭建xib,并添加一个拖拽的手势. 主控制器的代码:加载工具条 封装工具条以及手势拖拽的监听事件 此时运行 ...
- iOS | XIB简单应用和注意点
2018开篇第一篇文章,本文分享一点关于XIB的小知识,对于iOS开发新人来说或许有用. XIB 是 Interface Builder 的图形界面设计文档. 从Xcode 3.0 开始,苹果提供Xi ...
- iOS - XIB之AutoLayout添加约束
XIB--AutoLayout添加约束 仿QQ登录界面: 说明:以下各图背景红色只是方便看清楚: 1.创建工程:创建xib文件 2.打开xib文件: (1).创建头像: 拖控件:uiimageview ...
- ios xib 中的 size class
需要阅读UITraitCollection的说明文档,先截图如下: 今天说说xib中的size class的简单设置,先看图 一共有9个小块,水平方向代表width,垂直方向代表height. 对于w ...
- IOS, xib和storyboard的混用
1. 从xib的viewcontroll中启动storyboard 或者 从一个storyboard切换到另一个storyboard: [objc]– (IBAction)openStoryboard ...
- IOS xib在tableview上的简单应用(通过xib自定义cell)
UITableView是一种常用的UI控件,在实际开发中,由于原生api的局限,自定义UITableViewCell十分重要,自定义cell可以通过代码,也可以通过xib. 这篇随笔介绍的是通过xib ...
随机推荐
- inupt textarea提示文字(点击消失,不输入恢复)
<input name="textfield" type="text" maxlength="20" value="请输入 ...
- 安装cgdb
wget -c http://cgdb.me/files/cgdb-0.6.8.tar.gz .tar.gz cd cgdb- yum -y install texinfo help2man read ...
- Symfony电子商务
http://zhilihe.com/content/symfony%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1%E9%A1%B9%E7%9B%AE%E6%80%BB%E7 ...
- ftp -i -n -v <<! 其中 -n禁止自动登录到初始连接
<<!说明是输入.如是结束了需要再输入 !例如:ftp -i -n -v <<! 这里的叹号代表是ftp 命令的开始get 文件exit ! 代表ftp的命令 ...
- CalParcess.php.
<?php require_once "OperSerVice.class.php"; //接受三个数 //isset if(!isset($_REQUEST['NUM1'] ...
- android使用其他应用打开文件
根据文件的MIME类型来判断,手机中有哪些应用可以打开这个文件,然后把应用在弹窗列表中显示 /** * 打开文件 * * @param file */ public static void openF ...
- Java transient关键字序列化时使用小记
1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...
- [ios][opengles]opengles在ios上的透明问题
关于透明,OpenGL/ES 中可以通过 blend (混色) 来简单实现,混色的基本原理就是把要绘制的物体的颜色与屏幕上已经绘制好的颜色以一定比例来混合,最后的颜色看上去就像半透明一样.要使用混合先 ...
- 【转】使用JDK自带jvisualvm监控tomcat
转载地址: http://my.oschina.net/kone/blog/157239 jdk自带有个jvisualvm工具.该工具是用来监控java运行程序的cpu.内存.线程等的使用情况.并且使 ...
- session和cookie的总结
cookie在客户端保持,而session在服务器端保持. 1.cookie机制: 产生:服务器通过http协议的响应头,指示浏览器产生相应的cookie信息 使用:浏览器按照一定规则通过ht ...