大多数Ios开发者都喜欢运用xib以及约束来布局,这样省去了大量初始化代码,但是xib的使用也是存在不少差异的:
一.xib的几个重要属性
xib的文件名
File's owner
xib中的视图class
xib文件中的视图Outlet指向
二.Demo实现
1.加载xib中File's owner为nil的视图
blueView.png
ViewController:
- (void)addBlueView {
// BlueView.xib的File's Owner为nil
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"BlueView" owner:nil options:nil];
self.blueView = views[0];
// 从xib加载进来的View大小是确定的,但是该视图在父视图中的位置是不确定的
// 此外,视图中的子视图也是原封不动地Load进来的
CGRect rect = _blueView.frame;
rect.origin.x += 37.5f;
rect.origin.y += 80.0f;
_blueView.frame = rect;
[self.view addSubview:_blueView];
}
运行结果:
blueViewResult.png
总结:
File’s Owner为nil的xib文件中的视图属于通用视图,在工程中可以复用
从xib加载进来的View大小是确定的,但是该视图在父视图中的位置是不确定的,因此需要开发者自行指定
视图中的所有子视图会被原封不动地Load进来
2.加载File's owner为self的视图
greenView.png
ViewController
- (void)addGreenView {
// GreenView.xib的File's Owner设为self,并建立了一个从该xib的View到self的IBOutlet greenView
[[NSBundle mainBundle] loadNibNamed:@"GreenView" owner:self options:nil];
// 只要self主动调用Load XIB的方法,self持有的IBOutlet指向的视图就会被初始化
// 这里不需要通过views[0]的方式存取视图
CGRect rect = _greenView.frame;
rect.origin.x = _blueView.frame.origin.x;
rect.origin.y = _blueView.frame.origin.y + 80.0f;
_greenView.frame = rect;
[self.view addSubview:_greenView];
}
运行结果:
greenViewResult.png
总结:
File’s Owner不为nil的xib文件中的视图属于专用视图,在工程中不应该被复用
只要self主动调用loadNibNamed:owner:options:方法,self持有的IBOutlet指向的视图就会被初始化
存取xib中的视图不用views[0]的方式,而是通过IBOutlet类型的property进行存取
3.加载xib中File’s Owner为特定类的视图
redView.png
RedViewOwner:
@interface RedViewOwner : NSObject
@property (strong, nonatomic) IBOutlet UIView *redView;
@end
ViewController:
- (void)addRedView {
self.redViewOwner = [RedViewOwner new];
[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:self.redViewOwner options:nil];
UIView *redView = _redViewOwner.redView;
CGRect rect = redView.frame;
rect.origin.x = _greenView.frame.origin.x;
rect.origin.y = CGRectGetMaxY(_greenView.frame) + 30;
redView.frame = rect;
[self.view addSubview:redView];
}
结果:
redresult.png
总结:
File’s Owner类可以封装视图中的各种逻辑,而不仅仅是提供视图内容
只要通过File’s Owner类主动调用loadNibNamed:owner:options:方法,该IBOutlet指向的视图就会被初始化
4.加载xib中文件名和视图类名一致的视图(File’s Owner为nil)
yellowview.png
@implementation YellowView
+ (instancetype)loadYellowViewFromXib {
// 加载xib中的视图,其中xib文件名和本类类名必须一致
// 这个xib文件的File's Owner必须为空
// 这个xib文件必须只拥有一个视图,并且该视图的class为本类
NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
return views[0];
}
@end
ViewController:
- (void)addYellowView {
self.yellowView = [YellowView loadYellowViewFromXib];
CGRect rect = _yellowView.frame;
rect.origin.x = _redViewOwner.redView.frame.origin.x;
rect.origin.y = CGRectGetMaxY(_redViewOwner.redView.frame) + 30;
_yellowView.frame = rect;
[self.view addSubview:self.yellowView];
}
结果:
yellowresult.png
总结:
这里的viewFromNib方法只是对loadNibNamed:owner:options:方法的一个简单封装,要求的条件包括: - xib文件名和本类类名必须一致 - 这个xib文件的File’s Owner必须为空 - 这个xib文件必须只拥有一个视图,并且该视图的class为本类
5. 通过UIViewController的initWithNibName:bundle:方法加载xib文件中的视图
blackView.png
如果想要self.view是视图中的底层view,那么要连线File's owner 和view
blackviewll.png
BlackViewController
@interface BlackViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *label;
+ (instancetype)viewControllerFromNIB;
@end
+ (instancetype)viewControllerFromNIB {
return [[BlackViewController alloc] initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
}
ViewController
- (void)addBlackView {
self.blackVC = [[BlackViewController alloc] initWithNibName:@"BlackView" bundle:[NSBundle mainBundle]];
UIView *views = self.blackVC.view;
CGRect rect = views.frame;
rect.origin.x = _yellowView.frame.origin.x;
rect.origin.y = CGRectGetMaxY(_yellowView.frame) + 20;
views.frame = rect;
[self.view addSubview:views];
}
总结:
将xib的File’s Owner设成一个UIViewController子类,可以将这个xib文件的视图展示和外部响应事件(例如点击一个按钮触发的点击事件,该视图的手势事件等)全部封装在一个View Controller中,如果把按钮的点击事件封装在一个UIView类中,貌似破坏了MVC模式,因此最好将xib的File’s Owner设成一个UIViewController子类,该类可以通过addChildViewController方法将其添加到现有的View Controller上。如果只是希望加载视图,可以通过viewcontroller.view存取。
6. 通过UIViewController+NIB加载xib文件中的View Controller类和其视图
GrayView.xib
grayView.png
grayviewaction.png
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:NSStringFromClass(controllerClass) bundle:[NSBundle mainBundle]];
}
@end
GrayViewController.h/m
@interface GrayViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *actionButton;
@end
@implementation GrayViewController
- (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.actionButton setTitle:@"action" forState:UIControlStateNormal];
[self.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// 推荐从XIB文件中加载View Controller的方法,这种方法可以将XIB文件中的视图和其按钮响应事件全部封装在GrayViewController
// 如果GrayViewController的按钮响应事件由MainViewController作出响应,那么二者的耦合度就过高
// 建议:
// 单纯的通用View展示,使用从xib文件加载视图的方法,File's Owner设为nil
// 特定拥有者的View展示,从xib文件加载视图时,File's Owner设为拥有者
// 如果视图中有按钮响应事件,或其它可以和用户交互的事件,建议采用从XIB文件中加载View Controller的方法,这样可以封装UI展示和交互事件
- (IBAction)action:(id)sender {
NSLog(@"action");
}
@end
ViewController
...
@property (strong, nonatomic) GrayViewController *grayViewController;
...
- (void)loadGrayViewFromXIB {
self.grayViewController = [GrayViewController loadFromNib];
UIView *grayView = _grayViewController.view;
UIView *blackView = _blackViewController.view;
CGRect rect = grayView.frame;
rect.origin.x = blackView.frame.origin.x;
rect.origin.y = blackView.frame.origin.y + 80.0f;
grayView.frame = rect;
[self.view addSubview:grayView];
}
结果:
grayViewResult.png
总结:
这里我专门写了一个UIViewController+NIB的category,只需要调用loadFromNib类方法就可以加载xib中的视图。要求: - xib文件的File’s Owner必须设置为对应的View Controller类
三.总结
在写界面时同时混用xib和代码可以提高效率,而对xib的使用主要体现在其专用性和通用性上。
对于一些专门的界面,例如App中的设置界面,纯代码写难免会浪费时间,此时可以通过xib文件的拖控件方法来定制。这个xib是专用于某一个界面的,目的是提高效率
对于一些通用的控件甚至界面,例如一个很漂亮但实现起来非常复杂的按钮,此时可以通过load xib文件中的视图来快速添加。这个xib对于所有视图是共用的,目的是提高可复用性。
对于通用的xib:
如果xib只是单纯的界面展示,那么File’s Owner可以随意。
如果xib中包含了按钮、手势等用户输入事件,那么File’s Owner最好设置为UIViewController类的子类。
四.发现的问题
以前使用xib时一直都有点疑问,xib中可以有多个视图控件,但是从xib中load出来的是一个数组,那么怎么确定哪个对象对应的是哪个控件呢?
TestView.xib
testView.png
ViewController:
- (void)loadFromNib {
NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"TestView" owner:nil options:nil];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%ld----%@",idx,NSStringFromClass([obj class]));
}];
}
控制台输出如下:
2017-03-30 17:53:21.128 启动页[7655:288700] 0----UIView
2017-03-30 17:53:21.128 启动页[7655:288700] 1----UIButton
2017-03-30 17:53:21.128 启动页[7655:288700] 2----UITableView
2017-03-30 17:53:21.128 启动页[7655:288700] 3----UIImageView
结论:
从xib中load出来的views数组中视图对象的排列顺序和xib scene中的对象排列顺序一致(其实就是xml文件中元素的排序而已)。
result.png
# 视图高级笔记:### `add_url_rule(rule,endpoint=None,view_func=None)`这个方法用来添加url与视图函数的映射。如果没有填写`endpoint`,那么默认会使用`view_func`的名字作为`endpoint`。以后在使用`url_for`的时候,就要看在映射的时候有没有传递`en...
UIView 1.为什么要UIView .可以用UIView作为容器,存放子视图 .管理事件UIEvent 2.ios坐标系 以左上角为坐标原点,向右边是x的正方向,向下是y的正向方 bounds: 相对于视图本身而言(0,0,w, h) frame:相对于父视图的坐标 center: 相对于父视图的中心点坐标 3.将一...
最近项目中发现一怪问题,使用DB项目发布数据库时,总提示 “(110,1): SQL72014: .Net SqlClient Data Provider: Msg 1222, Level 16, State 56, Procedure sp_refreshsqlmodule_internal, Line 67 Lock reques...
转载地址:http://www.2cto.com/database/201212/176775.html 一、视图的基本介绍 www.2cto.com 视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。 使用视图需要MySQL5及以后的版本支持。 下面是视图的一些常见应用: 重用SQL语句; 简化复杂的S...
本例的初始文件是4位数字 (e.g. 0001.png),想在前面补1个0 (00001.png) import numpy as np import cv2 from ptsemseg.utils import recursive_glob import osroot = "./src/" root1 = "./dst/" fil...
方法一: QString file("sample.jpg"); if (file.contains(".jpg") || file.contains(".bmp") || file.contains(".png")) { qDebug()<<"这是图片。"; } 方法二: QString file_...
shell中可能经常能看到:>/dev/null 2>&1 命令的结果可以通过%>的形式来定义输出 分解这个组合:“>/dev/null 2>&1” 为五部分。 1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt 2:/dev/null 代表空设备文件 3:2> 表示stderr标准错误...
第三步,使用JODConverter将office文档转换为pdf JODConverter是一个java的OpenDucument文件转换器,可以进行许多文件格式的转换,它利用 OpenOffice来进行转换工作,它能进行以下的转换工作: 1.Microsoft Office格式转换为OpenDucument...