使用XIB实现嵌套自定义XIB视图
2015-11-02 14:52
281 查看
在进行
下面使用的示例代码我已经放到
首先我们创建一个
有时对于复杂的界面我们可能会拆分出来对它进行单独处理,又有可能它的界面布局很复杂,这时我们就会用
接下来对我们的界面进行布局,并连接输出口,编写响应逻辑,这里我放了一个
自定义的
这时,我们算是工作做完了,运行程序,结果悲剧了,怎么不是我们想要的结果,为什么只生成了两个空白的视图,我们视图上的图片和文字哪里去了?
在
那么如何解决这种问题,以及这种问题又是如何出现的呢?其实这主要是由于我们对
这样做
解决他们有两种方式,不过最终的思路都是通过代码强制使
这两种方法各有利弊,第一种使用起来方便也好理解,但是当嵌套的层级比较多的时候或者一个
先来介绍第一种方法,很简单,就是找到
第二种方法是通过重载
此外,还要这里的输出口以及设置
这个时候在运行程序就看到了我们想要的结果了。 _^
其实想要实现第二种解决方案所要的效果,还有一种方式,它是通过重载
原文:http://blog.wtlucky.com/blog/2014/08/10/nested-xib-views/
iOS开发的过程中,对于一些复杂的界面,我们可以通过
Interface Builder这个
Xcode集成的可视化界面编辑工具在完成,这回节省大部分时间以及代码量。它的使用方法这里不做介绍了,这次我要介绍是使用它来实现一个嵌套的自定义视图。解释一下就是,我们使用
IB自定义了一个
View,然后又在其他的
xib文件中使用了这个
View,那么这就是所谓的嵌套自定义视图。之所以要介绍它,是因为我自己在使用它的时候遇到了一些问题,一方面写下来做个记录供自己查看,另一方面我相信大家在使用的时候应该也会遇到这样的问题,方便大家。
下面使用的示例代码我已经放到
Github上了, 项目地址 ,有需要的朋友可以去查看,
Demo非常简单,主要是介绍这个知识点。
Question
首先我们创建一个 SingleView的工程,项目使用
StoryBoard,(使用
Xib也无所谓,因为有些老的项目可能还没有使用到
StoryBoard),然后创建一个
CustomView作为我们的自定义视图。
有时对于复杂的界面我们可能会拆分出来对它进行单独处理,又有可能它的界面布局很复杂,这时我们就会用
Interface Builder对它的布局进行处理。这里的
CustomView就是这样一个视图,所以我们为它创建一个
xib文件,我们通常的作法就是把
xib中的
View的
custom class更改为我们的
CustomView。
接下来对我们的界面进行布局,并连接输出口,编写响应逻辑,这里我放了一个
ImageView和一个
Label在这里,并把
View的背景色设置为浅灰色。
自定义的
View制作完成,回到我们
ViewController的
xib文件,拖入两个
View并把他们的
custom class更改为
CustomView。
这时,我们算是工作做完了,运行程序,结果悲剧了,怎么不是我们想要的结果,为什么只生成了两个空白的视图,我们视图上的图片和文字哪里去了?
在
CustomView中的
awakeFromeNib方法中增加断点调试发现,在
CustomView初始化完成后,
ImageView和
Label并没有被初始化,他们仍然是
nil。这就是在嵌套使用
xib自定义视图时非常容易出现的问题,我们觉得被嵌套的视图能够正常显示出来,但是实际上它并没有被按照我们在
xib上指定的方式被初始化。
Solution
那么如何解决这种问题,以及这种问题又是如何出现的呢?其实这主要是由于我们对 xib文件的加载原理不熟悉所导致的,我们以为定义一个
View,创建一个
xib文件并布局好它的子视图,让后将它使用在另外一个
xib文件中,把
custom class改成它,然后
xib的加载系统会自动为我们做好其余的一切。其实并不是这样的。
这样做
xib加载系统只会为我们创建一个
CustomView的对象,但这并不包括
CustomView所对应的
xib文件中的部分,所以只创建了一个空白的
View。
解决他们有两种方式,不过最终的思路都是通过代码强制使
CustomView的
xib部分被加载。第一种是通过代码创建
CustomView的对象,然后
addSubview到
viewController的
view上。第二种是在
CustomView的实现文件里,通过重载一些方法,来完成加载
xib文件。
这两种方法各有利弊,第一种使用起来方便也好理解,但是当嵌套的层级比较多的时候或者一个
View中有多个这样的
CustomView时,这种方式就会显得过于麻烦。而第二种虽然理解起来有些难度,但是当你处理好之后,直接在需要的
xib文件中拖入
view,改个
custom class,就能直接生成需要的对象了,并且也能够在
xib中对他们进行直接布局,不再需要用代码去布局了。
NO 1.
先来介绍第一种方法,很简单,就是找到 xib文件,生成对象,设置属性,
addsubview到视图上。
NO 2.
第二种方法是通过重载 initWithCoder方法来实现,因为通过
xib来创建一个对象会调用到这个方法,所以我们需要在这个方法里做一些处理,把这个
CustomView的
xib中的内容加载进来,这时同样是需要通过代码来来加载,首先附上代码
- (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super initWithCoder:aDecoder]) { UIView *containerView = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]; CGRect newFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); containerView.frame = newFrame; [self addSubview:containerView]; } return self; } |
custom class的位置跟第一种方式有所不同,这里需要取消掉
xib中
view的
custom class,再将跟它连接的图片与文字的输出口取消掉,在这里这个
view只是被当做一个容器来处理,它跟
Customview没有直接关系,它将来会被
addSubview到
CustomView上,除此之外还要把
xib的
File's ower的
custom class改成
CustomView,表示这个
xib文件的持有者是
CustomView。再把它与图片和文字通过输出口连接起来。
这个时候在运行程序就看到了我们想要的结果了。 _^
其实想要实现第二种解决方案所要的效果,还有一种方式,它是通过重载
awakeAfterUsingCoder:方法来实现的,这个方法的返回值会替换掉真正的加载对象,所以在具体的加载
CustomView的方式又与第一种相同,所以
xib的输出口连接与
custom class的设置也与第一种解决方案相同。不过这种方式是更复杂也更难于理解的,不推荐使用,因为上一个方法就能很好的解决这个问题了,这里只是贴出这个方法的代码,有想仔细研究的请参看文章底部的参考文章。
- (id) awakeAfterUsingCoder:(NSCoder*)aDecoder { BOOL isJustAPlaceholder = ([[self subviews] count] == 0); if (isJustAPlaceholder) { CustomView* theRealThing = [[self class] getClassObjectFromNib]; theRealThing.frame = self.frame; // make compatible with Auto Layout self.translatesAutoresizingMaskIntoConstraints = NO; theRealThing.translatesAutoresizingMaskIntoConstraints = NO; // convince ARC that we're legit, unnecessary since at least Xcode 4.5 CFRelease((__bridge const void*)self); CFRetain((__bridge const void*)theRealThing); return theRealThing; } return self; } |
相关文章推荐
- 淘宝穿衣搭配算法_方案四
- 大话数据结构——第一、二章
- 大杂烩
- Core Data 入门
- MVC下载远程文件流(WebClient)
- SharePoint 2010 升级到SharePoint 2013的流程
- hihoCoder挑战赛16 A—— 王胖浩与三角形
- WampServer 多站点域名访问配置教程
- set方法的调用在内存管理中
- StoryBoard之User Defined Runtime Attributes的使用
- arp resolution
- Invoke BeginInvoke
- (原创)c#学习笔记08--面向对象编程简介01--面向对象编程的含义03--静态和实例类成员
- Android 系统联系人全特效实现(下),字母表快速滚动
- Word & exel? The setup controller has encountered a problem during install.
- Linux内核和用户空间应用程序的接口—系统调用
- java中从键盘输入的三种方法
- jQuery源码分析之ajaxTransport和ajaxPrefilters执行函数之inspectPrefiltersOrTransports
- javascript 学习总结(九)面向对象编程
- Ubuntu中Vim 中文乱码解决方法