为UIView自定义Xib
一、需求
通过Interface Builder的形式创建Xib,并将其和一个UIView的子类绑定,如何实现?
二、解决
这个问题通过搜索,有大量的答案,大概答案的代码如下:

也就是在你的子类中,在初始化方法initWithFrame、initWithCoder中主动加载一个xib对应的类,作为子view添加到当前的view中
这种方式,会明显产生一个问题,会产生两个相同的自定义View对象


先不说两个View带来的危害,可能导致业务代码的冲突,最关键的是,xib中拖出的reference指向只能在loadnib返回的对象中初始化好,你自定义的对象的指向为空。
这样太坑爹了
这也是下面这个问题产生的原因,想通过修改initwithCoder的返回值为自己主动反序列化xib产生的对象


这种方案我也测试了,测试代码如下:
#import "XibHackInit.h" @implementation XibHackInit - (instancetype)initWithCoder:(NSCoder *)aDecoder
{
static BOOL alreadyInitMark = NO;
if(self = [super initWithCoder:aDecoder])
{
if(!alreadyInitMark)
{
NSString *className = NSStringFromClass([self class]);
if([className containsString:@"."])
{
className = [[className componentsSeparatedByString:@"."] lastObject];
}
alreadyInitMark = YES;
UIView *targetView = [[self class] loadFromNib:className];
alreadyInitMark = NO;
return (XibHackInit *)(targetView?targetView:self);
}
}
return self;
} + (UIView *)loadFromNib:(NSString *)nibName
{
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
options:nil];
UIView* nibView = (UIView*)[nibViews objectAtIndex:0];
return nibView;
} @end
注意initWithCoder中用了一个BOOL变量,这个变量主要是为了避免产生的递归,loadFromNib方法一调用、又会调用到initWithCoder中,简直就成了一个不可解的死bug
上面的代码是OC实现的,为什么不用swift实现,主要是因为swift中init方法除了返回空值之外,不能返回其他值
这么做的结果是什么呢?程序直接Crash

有没有更优美的方案?
这里的折中方案是,先创建一个容器View,在容器View中加载你想要的子View,这样可以充分考虑到Xib中复用的问题
效果:


除了清晰的View层次之外,还可以在Interface Builder中进行可视化,实现的关键代码如下:

核心代码:
import UIKit @IBDesignable
class XibElementContainer: UIView { var elementView:UIView?
@IBInspectable var elementNibName:String? override func awakeFromNib() {
super.awakeFromNib()
xibSetup()
} func xibSetup() {
guard let view = loadViewFromNib() else { return }
view.frame = bounds
view.autoresizingMask =
[.flexibleWidth, .flexibleHeight]
addSubview(view)
elementView = view
} func loadViewFromNib() -> UIView? { guard let nibName = elementNibName else { return nil }
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(
withOwner: self,
options: nil).first as? UIView
} override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
xibSetup()
elementView?.prepareForInterfaceBuilder()
}
}
有两个关键字:
@IBDesignable InterfaceBuilder 会尝试对这个类的对象进行可视化,会调用prepareForInterfaceBuilder方法
@IBInspectable InterfaceBuilder 会显示这个字段的输入框,可以在界面上面直接输入值

三、最终代码
代码:https://github.com/liqiushui/CustomXibForUIView
为UIView自定义Xib的更多相关文章
- 5 approach to load UIView from Xib
After the past few years I found that the only manageable way for creating/maintaining view (or any ...
- Swift下自定义xib添加到Storyboard
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51657154 ...
- 实现自定义xib和storyboard的加载,
一:加载xib 1.分别创建xib,.h .m文件继承自UIView. 在xib上绑定类名. 或者创建文件的时候直接勾选xib 2.在控制器中调用类方法 jyq52787网盘/ios/潭州学院/iO ...
- Xcode5 创建模板和UIView 关联XIB
转自:http://www.cnblogs.com/china-ldw/p/3533896.html 在做ios应用开发的过程,难免遇到要创建 子view 和 自定义view的时候,归根到底,我们需要 ...
- ios --xib自定义,解决在导航栏不透明的情况下,自定义xib view高度被压缩64的问题
在使用xib自定义view的时候,个人习惯性的直接使用xib中的约束,所以自然而然的要打开Autolayout.以前在使用的时候没有发现什么问题,最近项目中使用的时候突然发现在导航栏透明的情况下,出现 ...
- iOS 给UIView添加xib
2017-08-25编辑:这文章有点过时了 推荐新的文章:http://www.cnblogs.com/hero11223/p/6881848.html 一段时间没敲代码,以前一些简单的都不会做了,翻 ...
- uiview关联xib
1,在需要实例的地方 //加载一个uiview的作法 [LotteryInvestigationView *lotteryInvestigationView=[[[NSBundle mainBundl ...
- 自定义 XIB subview的时候 为什么控件都是 空的
http://blog.wtlucky.com/blog/2014/08/10/nested-xib-views/
- UIView创建xib
这里有两种类都可以实现,但是推荐用Empty类来创建 (Empty): 参考链接:https://blog.csdn.net/wtdask/article/details/76439295 https ...
- 从Xib文件加载UIView的5种方式
在不同的Xib文件中最容易维护的是定义的视图,因此对于从Xib文件中加载UIView来说一个方便的流程是非常重要. 在过去的几年里我发现唯一易于管理创建和维护视图(或者任何界面元素,通常会更多)方式就 ...
随机推荐
- sql 语句系列(列举系列)[八百章之第八章]
前言 这一张就是就是查询自己设计数据库的结构,对于接收一个老的项目相当重要. 列举模式中的表 查询所以表 select table_name from INFORMATION_SCHEMA.TABLE ...
- 2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」。 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值。勇者们有一次机会可以击破一个节点泡
2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」. 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值.勇者们有一次机会可以击破一个节点泡 ...
- super()和super(props)
一.ES6类 在ES6中,通过extends关键字实现类的继承,方式如下: class sup { constructor(name) { this.name = name } printName() ...
- Dubbo 3.0 前瞻系列 | 2020双11,Dubbo3.0 在考拉的超大规模实践
很多开发者一直以来好奇:阿里自己有没有在用Dubbo,会不会用Dubbo?在刚刚结束的双11,我们了解到阿里云今年提出了"三位一体"的理念,即将"自研技术".& ...
- OceanBase时序数据库CeresDB正式商用 为用户提供安全可靠的数据存储管理服务
简介: OceanBase完成OLAP和OLTP双重能力并行后,向数据管理领域多模方向迈出第一步. 近日,在数据库OceanBase3.0峰会上,OceanBase CEO杨冰宣布首个时序数据库产品C ...
- LVGL 字体
一.LVGL 内置字体 LVGL有几种不同大小的内置字体,可以通过 LV_FONT_MONTSERRAT_X 定义在 lv_conf.h 中启用. 普通字体 包含所有ASCII字符,度数符号(U + ...
- LVGL 显示图片
一.图片存储 我们可以将图像存储在两个位置 作为内部存储器(RAM或ROM)中的变量 作为文件 图片以文件的形式存储在文件系中(比如SD),需要打开LVGL的文件操作的功能(打开,读取,关闭等).虽然 ...
- IIS相关发布错误解决记录
HRESULT 代码 0x80070021 错误消息: 应用程序"应用程序名称"中的服务器错误HTTP 错误 500.19 - 内部服务器错误HRESULT:0x80070021对 ...
- Codeforces Round 917 (Div. 2)
A. Least Product 存在 \(a[i] = 0\),\(min = 0\),不需要任何操作. 负数个数为偶数(包括0),\(min = 0\),把任意一个改为 \(0\). 负数个数为奇 ...
- Unity 热更--AssetBundle学习笔记 1.0【AB包资源加载工具类的实现】
工具类封装 通过上文中对AB包加载API的了解和简单使用,对AB包资源加载的几种方法进行封装,将其写入单例类中,如代码展示. 确保每个AB资源包只加载一次: 在LoadAssetBundleManag ...