在iOS的开发中究竟是用纯代码还是使用xib一直是大部分人争论的一个问题。用纯代码开发逻辑清晰,便于维护,用xib开发界面直观,开发方便,可以说是各有各的优点,我认为如果在开发中可以将xib与代码结合,那么可以大大的提高我们的开发效率,在这里我将xib的使用做一下简单的介绍。
普通视图的xib文件加载
1 创建xib文件
在你需要的地方创建xib文件
此处选择View和Empty效果相差不多,不同的就是选择View创建完成之后会默认有一个View,选Empty则默认是空的需要自己添加View
添加好名字之后直接点击创建完成xib的创建
如果创建的时候选择的是Empty需要我们自己添加一个空白的View,如图找到控件后将其添上
右方的属性设置按钮里边可以对我们选中的控件进行设置(此处设置的内容会根据选中的不同的控件有不同的改变),所以视图中的控件属性我们都可以在这边进行设置。注意如果想自由设置尺寸一定要在属性的Size中选择FreeForm,否则尺寸设置为灰色,不可改变。
3 创建xib文件关联的类并与xib进行关联:创建与其关联的类可以实现xib与代码结合开发,并且在在关联的类中对xib进行设置也比较符合面向对象的封装思想。值得注意的就是创建类的继承,根据xib的不同类型选择不同的继承,比如此案例中xib就是一个UIView所以我们创建的类也要继承UIView,如果我们创建的xib是一个UITableViewCell我们创建类就要继承UITableViewCell。创建完成之后与xib进行关联,方法如下:
如果添加的时候此处没有默认提示就说明继承可能出现问题了,注意观察
4 设置xib
接下来就可以将需要的控件添加在View中(控件中的字体颜色,背景,内容等都可以在前边说到的属性设置按钮中进行设置),为了适配不同的屏幕建议在此处采用自动布局设置控件的位置(最早也有采用根据不同屏幕宽度创建不同宽度的xib,然后加载的时候判断屏幕宽度加载不同宽度的视图,这样虽然也能实现适配,但是相比自动布局来说复杂太多了,所以现在很少有这么用的了)。
5 拖线:xib中的控件都可以通过拖线到刚刚相关联的类中,通过此方法可以在关联类中获得控件对其进行相关赋值或者设置
可以根据图片中的方法打开关闭分栏,也可以通过快捷键按住option+鼠标左键点击关联类打开分栏进行拖线,拖线结束后按住command+return(回车)关闭分栏
注:如图拖拽到延展中成为私有属性,只能在此类中获得,外界无法获取赋值,拖拽到类的.h文件中成为公开属性外界可以获取
通过拖线除了获得控件外还能直接生成一些事件,最常用的就是按钮的点击事件,可以通过直接将线拖拽到@implementation中实现
注意:如果把拖线得到的属性或者方法删除了一定要记得右键对应的控件将其中的线也删除,否则程序会崩溃(切记,因为这条线非常容易被忽略所以删除后一定记得删除对应的线)。
拖拽完成之后效果如图:
为了符合封装思想所以对于此xib的后期设置我们将全部在这个与其关联的类中实现,控制器只负责对其进行加载,这样也可以大大的减少控制器中的代码
6 加载此xib视图
在控制器的viewDidLoad中加载此视图,加载代码如下:
// 为了区分视图,将控制器view的颜色设置为绿色
self.view.backgroundColor = [UIColor greenColor];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
// owner传nil默认为self
TestView *testView = [[[NSBundle mainBundle] loadNibNamed:@"TestView" owner:nil options:nil] firstObject];
testView.frame = CGRectMake(0, 0, width, height * 0.5);
[self.view addSubview:testView];
加载之后的视图运行结果如图:
前边提到了也可以将空间拖拽到,h文件中成为公开属性,这样外界也可以获取到直接给其赋值
// 为了区分视图,将控制器view的颜色设置为绿色
self.view.backgroundColor = [UIColor greenColor];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
TestView *testView = [[[NSBundle mainBundle] loadNibNamed:@"TestView" owner:nil options:nil] firstObject];
testView.frame = CGRectMake(0, 0, width, height * 0.5);
[self.view addSubview:testView];
// .h文件中声明的属性外界可以获取并进行赋值或者修改
testView.xibLabel.text = @"这是一个用来测试的Label";
加载UITableViewCell类型的xib
在UITableView的cell中和UICollectionView的item中xib的使用也比较多,用起来也比较方便,因为这两个控件都涉及到一个重用所以加载的时候与普通的视图加载稍微有一点点的不同,在这里我采用UITableView做一下简单的介绍
1 创建UITableViewCell的xib文件和与其相关联的类(注意继承UITableViewCell),创建方式与上边相同,并且通过拖线的方式在关联类中获得控件
2 创建UITableView控件并设置好代理与数据源
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *mainTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-20)];
[self.view addSubview:mainTableView];
mainTableView.dataSource = self;
mainTableView.delegate = self;
}
为了查看效果,数据源中的数据都是自己写死的一些数据,数据源数组采用懒加载的方式创建,将每一个cell的图片、标题、描述都储存在一个对应的字典中,然后放在数据源数组中,共有20条数据
- (NSArray *)dataSourceArr{
if (!_dataSourceArr) {
_dataSourceArr = [NSArray array];
NSMutableArray *tepArrM = [NSMutableArray array];
for (int i = 0; i < 21; i++) {
NSDictionary *cellDict = @{@"icon":[NSString stringWithFormat:@"%@",@(i)],
@"title":[NSString stringWithFormat:@"我是标题%@",@(i)],
@"desc":[NSString stringWithFormat:@"我是第%@个cell",@(i)]};
[tepArrM addObject:cellDict];
}
_dataSourceArr = tepArrM.copy;
}
return _dataSourceArr;
}
3 因为UITableView控件涉及到一个重用,所以我们如果按照上边的加载方法加载就会每次创建一个新的cell就没有了重用的功能,我们可以通过两种途径解决他的重用
a)在xib的属性设置中设置重用标示符,此标示符要和创建cell使用的标示符相同
b)采用与UICollectionView相同的注册xib的方法:
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *mainTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-20)];
[self.view addSubview:mainTableView];
mainTableView.dataSource = self;
mainTableView.delegate = self;
// 注册xib
[mainTableView registerNib:[UINib nibWithNibName:@"XibTestCell" bundle:nil] forCellReuseIdentifier:@"xibTestCell"];
}
此处的标识符也是一定要和下边用到的标识符相同
4 实现UITableView的数据源方法和代理方法:
// 返回cell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 80;
}
// 返回一共有几个section,如果不实现默认为1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
// 返回每个section中有几行,根据数据中的个数决定,有几个数据就返回几个cell
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.dataSourceArr.count;
}
最后一个方法就是返回每个cell对应的样式,我们可以在这个方法中加载刚才设置的xib,并且将每个cell对应的数据传到xib对应的类中,因为前边提到了每个cell都会对应一个字典,所以在此之前我们需要在xib关联的类中的.h文件中声明一个字典用来接收每个cell对应的数据
之后实现数据源的最后一个方法
// 返回每个cell对应的样式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 可重用的标示符
static NSString *ID = @"xibTestCell";
XibTestCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
// 加载xib文件(cell)
cell = [[[NSBundle mainBundle]loadNibNamed:@"XibTestCell" owner:self options:0] firstObject];
}
// 将每组cell对应的数据传递到xib对应的类中通过重写setter方法对其每个cell进行赋值
cell.infoDict = self.dataSourceArr[indexPath.row];
return cell;
}
5 在xib文件对应的类中为每个cell进行对应的赋值
// 通过重写setter方法对每个控件进行赋值
- (void)setInfoDict:(NSDictionary *)infoDict{
_infoDict = infoDict;
// 图片名称
NSString *iconName = infoDict[@"icon"];
// 标题内容
NSString *title = infoDict[@"title"];
// 标题底部描述内容
NSString *desc = infoDict[@"desc"];
// 为控件赋值
self.iconView.image = [UIImage imageNamed:iconName];
self.titleLabel.text = title;
self.descLabel.text = desc;
}
此类的.m文件整体内容如图:
通过此种方法可以实现通过xib自定义cell然后为其赋值,最后展现出来的模拟器截图如下:
总结
因为使用xib加载单个UIView和加载UITableViewCell以及UICollectionViewItem是开发中使用频率相对较高的,而加载cell和item原理相同,所以在这里采用这两个小案例对xib的使用做一下简单的介绍希望能帮到一部分朋友,另外对于自己也是一个学习的加强与提升。