一、需求

 通过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. android虚拟机硬件加速问题

    前言 创建的android 虚拟机的如果我们选择x86,那么会出现需要硬件加速. 步骤 那么打开虚拟功能后可以进行安装,SDK Manager-> Extras->Intel Hardwa ...

  2. Pytorch Dataset入门

    ​ Dataset入门 Pytorch Dataset code:torch/utils/data/dataset.py#L17 Pytorch Dataset tutorial: tutorials ...

  3. labelme转coco数据集

    原始labelme数据目录结构如下: |-- images | |--- 1.jpg | |--- 1.json | |--- 2.jpg | |--- 2.json | |--- ....... | ...

  4. 实训篇-Html-计算器

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 剑指offer29(Java)-顺时针打印矩阵(简单)

    题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5 ...

  6. 21克:仅需3天,我们就用Quick BI搭建起数据驾驶舱

    ​简介:数智化并不仅仅是大型企业才需要去思考的课题,而是摆在所有企业面前的一个可选项.借助Quick BI搭建的数据分析体系,21克实现了销售.财务.供应链等多部门业务的数据化支撑,从一份份本地化的E ...

  7. 庖丁解InnoDB之UNDO LOG

    ​简介: Undo Log是InnoDB十分重要的组成部分,它的作用横贯InnoDB中两个最主要的部分,并发控制(Concurrency Control)和故障恢复(Crash Recovery),I ...

  8. WPF 基础 2D 图形学知识 判断点是否在线段上

    在知道一个使用两个点表示的线段,和另一个点,求另一个点是否在线段上 本文算法属于通用的算法,可以在 WPF 和 UWP 和 Xamarin 等上运行,基本上所有的 .NET 平台都能执行 如下图,如果 ...

  9. k3s安装---适配边缘计算场景的轻量级的k8s(二)

    三.安装k8s k3s官网:https://k3s.io 文档: github:https://github.com/k3s-io/k3s 3.1 安装基础环境 # 安装基础环境 1.安装yum源 c ...

  10. RT-Thread 堆区大小设置

    一.利用栈区的空间作为堆区 看过我之前的笔记的小伙伴都知道,以前我是通过申请栈区的空间使用的,感兴趣的小伙伴可以看我之前的笔记,RT-Thread移植到stm32. 在board.c文件文件中的代码如 ...