一、需求

 通过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的更多相关文章

  1. 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 ...

  2. Swift下自定义xib添加到Storyboard

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51657154 ...

  3. 实现自定义xib和storyboard的加载,

    一:加载xib 1.分别创建xib,.h  .m文件继承自UIView. 在xib上绑定类名. 或者创建文件的时候直接勾选xib 2.在控制器中调用类方法 jyq52787网盘/ios/潭州学院/iO ...

  4. Xcode5 创建模板和UIView 关联XIB

    转自:http://www.cnblogs.com/china-ldw/p/3533896.html 在做ios应用开发的过程,难免遇到要创建 子view 和 自定义view的时候,归根到底,我们需要 ...

  5. ios --xib自定义,解决在导航栏不透明的情况下,自定义xib view高度被压缩64的问题

    在使用xib自定义view的时候,个人习惯性的直接使用xib中的约束,所以自然而然的要打开Autolayout.以前在使用的时候没有发现什么问题,最近项目中使用的时候突然发现在导航栏透明的情况下,出现 ...

  6. iOS 给UIView添加xib

    2017-08-25编辑:这文章有点过时了 推荐新的文章:http://www.cnblogs.com/hero11223/p/6881848.html 一段时间没敲代码,以前一些简单的都不会做了,翻 ...

  7. uiview关联xib

    1,在需要实例的地方 //加载一个uiview的作法 [LotteryInvestigationView *lotteryInvestigationView=[[[NSBundle mainBundl ...

  8. 自定义 XIB subview的时候 为什么控件都是 空的

    http://blog.wtlucky.com/blog/2014/08/10/nested-xib-views/

  9. UIView创建xib

    这里有两种类都可以实现,但是推荐用Empty类来创建 (Empty): 参考链接:https://blog.csdn.net/wtdask/article/details/76439295 https ...

  10. 从Xib文件加载UIView的5种方式

    在不同的Xib文件中最容易维护的是定义的视图,因此对于从Xib文件中加载UIView来说一个方便的流程是非常重要. 在过去的几年里我发现唯一易于管理创建和维护视图(或者任何界面元素,通常会更多)方式就 ...

随机推荐

  1. CentOS6.5安装与配置JDK-7

    系统环境:centos-6.5 安装方式:rpm安装 软件:jdk-7-linux-i586.rpm 下载地址:http://www.oracle.com/technetwork/java/javas ...

  2. React中的key的作用

    一.是什么 首先,给出react组件中进行列表渲染的一个示例: const data = [ { id: 0, name: 'abc' }, { id: 1, name: 'def' }, { id: ...

  3. SVM简单分类的使用 sklearn机器学习

    # sklearn 库中导入 svm 模块 from sklearn import svm # 定义三个点和标签 X = [[2, 0], [1, 1], [2,3]] y = [0, 0, 1] # ...

  4. C++ 构造函数实战指南:默认构造、带参数构造、拷贝构造与移动构造

    C++ 构造函数 构造函数是 C++ 中一种特殊的成员函数,当创建类对象时自动调用.它用于初始化对象的状态,例如为属性分配初始值.构造函数与类同名,且没有返回值类型. 构造函数类型 C++ 支持多种类 ...

  5. OceanBase初体验之部署生产标准的三节点分布式集群

    前置条件 OceanBase 数据库集群至少由三个节点组成,所以先准备好3台服务器: IP 配置 操作系统 x.x.x.150 Intel x86 12C 64G内存 1T SSD CentOS 7. ...

  6. 友盟+U-APM 移动应用性能体验报告:Android崩溃率达0.32%,OPPO 、华为、VIVO 崩溃表现良好

    简介: 应用性能稳定是良好用户体验中非常关键的一环,而现实情况却是应用崩溃.卡顿.加载缓慢.页面白屏等问题,频频出现在用户的真实体验之中,成为影响业务表现的直接杀手.为此,应用性能管理(APM)正在国 ...

  7. dotnet SemanticKernel 入门 将技能导入框架

    在上一篇博客中和大家简单介绍了 SemanticKernel 里的技能概念,接下来咱准备将 技能 导入到 SemanticKernel 框架里面,进行一个管道式调用 本文属于 SemanticKern ...

  8. Python采集知网

    Python爬虫初探 selenium+beautifulsoup4+chromedriver 安装模块:* import pymssql* pip install bs4* pip install ...

  9. SQL server 树形递归查询

    1,原始查询 原始表格查询: select * from dbo.T_DeptInfo; 原始表格查询结果: 2,递归查询 -- with 一个临时表(括号里包括的是你要查询的列名) with tem ...

  10. JUC并发编程学习笔记(二)Lock锁(重点)

    Lock锁(重点) 传统的synchronized 传统的解决多线程并发导致的一些问题我们会使用synchronized关键字来解决,synchronized的本质就是队列.锁. Lock的实现类有: ...