文档章节

在Storyboard中使用由xib定义的view

丨王天雨丨
 丨王天雨丨
发布于 2016/09/26 22:52
字数 1129
阅读 26
收藏 0

前言

在iOS开发中,使用storyboard的某些场景下我们可能希望同时使用xib定义一些可以重复利用的view,并在storyboard中调用。本文将分享一种此类xib bridge的简单实现方式。

实现思路

本方法的思路是将xib的File's Owner所对应的UIView作为placeholderView,其作用只是在storyboard中起到占位作用,并承载storyboard中与xib自定义view相关的AutoLayout约束,其背景色将被设为[UIColor clearColor],并且不显示任何内容。显示自定义内容的任务将交给一个UIView--contentView,它将作为placeholderView的子视图。

为了使在storyboard中作用于placeholderView的AutoLayout约束能够自动的作用于contentView,可以向placeholderView添加NSLayoutRelationEqual约束,让placeholderViewcontentView的上下左右四个NSLayoutAttribute分别完全相等,这样contentView在storyboard中的的frame将完全和placeholderView相同,从而达到目的。

以上方法同样可以适用于xib的某个子view是另外一个xib的情形。

实现方法

首先进行如下准备工作

  • 创建一个xib,用于实现子view的自定义内容,本文中命名为CoverView.xib
  • 创建一个UIView的子类,作为placeholderView的基类,用于进行xib bridge相关的添加约束和添加contentView等工作,本文中命名为XibBridgeBaseView
  • 创建一个XibBridgeBaseView的子类,用于存储xib中自定义内容的相关属性并进行相关操作,本文中命名为CoverView

实现子view的xib文件

首先需要在identity inspector中将xib文件的File's Owner设置成为创建好的CoverView

Files-Owner-identity-inspector.jpg

接下来我们就可以在xib中自动创建的UIView子视图中进行自定义UI了,此时可以在CoverView类中创建该UIView子视图(这里命名为contentView)以及其他UI组件的IBActionIBOutlet等。

setup-IBOutlet-and-IBAction.jpg

实现占位视图的基类

作为placeholderView的基类,XibBridgeBaseView中定义了如下的一个方法,用于从nib中载入contentView并添加进占位视图的子视图中,其中XibBridgeBaseViewinitWithCoder:方法将使用其派生子类的类名作为xib的名字,因此子类和其所对应的xib文件应该使用相同的命名。

@implementation XibBridgeBaseView
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setupXibBridgeWithPlaceholderViewNibName:NSStringFromClass([self class])];
    }
    return self;
}

- (void)setupXibBridgeWithPlaceholderViewNibName:(NSString *)placeholderViewNibName {
    UIView *contentView =[[[NSBundle mainBundle] loadNibNamed:placeholderViewNibName
                                                        owner:self
                                                      options:nil] objectAtIndex:0];
    
    [self setBackgroundColor:[UIColor clearColor]];
    [self addSubview:contentView];
    [self setXibBridgeConstraintsToContentView:contentView];
}

其中- (void)setXibBridgeConstraintsToContentView:(UIView *)contentView方法主要是实现前文提到的通过向占位视图添加NSLayoutRelationEqual约束让placeholderViewcontentView的上下左右四个NSLayoutAttribute分别完全相等:

@implementation XibBridgeBaseView
- (void)setXibBridgeConstraintsToContentView:(UIView *)contentView {
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|"
                                                                options:0
                                                                metrics:nil
                                                                  views:NSDictionaryOfVariableBindings(contentView)]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|"
                                                                options:0
                                                                metrics:nil
                                                                  views:NSDictionaryOfVariableBindings(contentView)]];
    //为保证AutoLayout生效,必须加上下面这句话
    contentView.translatesAutoresizingMaskIntoConstraints = NO;    
}

实现占位视图的实际类

作为placeholderView的实际类,每创建一个需要被桥接的xib时就要创建一个对应的实际类(本文中为CoverView类),CoverView中将包含在xib中定义的自定义UI相关的属性和操作:

@interface CoverView : XibBridgeBaseView

@property (weak, nonatomic) IBOutlet UILabel *headerLabel;
@property (weak, nonatomic) IBOutlet UIButton *submitButton;
@property (strong, nonatomic) IBOutlet UIView *contentView;
@implementation CoverView
- (IBAction)submitButtonClicked:(UIButton *)sender {
    NSLog(@"Hello World!");
}

因为我们是用父storyboard或者xib来调用placeholderView的,实际使用中只需要将placeholderView的实际类继承于基类xibBridgeBaseView,即可实现桥接功能。该placeholderView的其他初始化工作可以放在- awakeFromNib中进行

@implementation CoverView
- (void)awakeFromNib {
    self.contentView.backgroundColor = [UIColor clearColor];
    [self.contentView.layer setBorderColor:[[UIColor whiteColor] CGColor]];
    [self.contentView.layer setBorderWidth:1.0];
}

在父的storyboard或者xib中调用placeholderView

做完以上步奏后,只需在父storyboard或者xib中拖一个UIView来作为placeholderView,并在identity inspector中将其class属性设置成为对应的placeholderView的实际类即可。

set-class-for-placeholderView-in-storyboard.jpg

结语

在使用如上方法来进行xib桥接的过程中需要注意一下几点使用方式:

  • 在父的storyboard或者xib中,只需要对拖入的placeholderView添加AutoLayout约束即可
  • 在子xib中各个UI组件只需要跟contentView建立AutoLayout约束即可
  • 对于placeholderView的identity inspector相关参数需要在子xib中对File's Owner进行设置
  • 对于placeholderView的attribute inspector相关参数需要在父storyboard或者xib中进行设置

对于xib桥接问题大神SUNNYXX给出了一个更高端的解决方案,利用到了iOS runtime相关的技术。


本文个人博客地址: http://wty.im/2016/02/29/use-view-defined-by-xib-in-storyboard/ Github: https://github.com/wty21cn/

© 著作权归作者所有

丨王天雨丨
粉丝 0
博文 5
码字总数 5157
作品 0
朝阳
程序员
私信 提问
iOS 5的StoryBoard

StoryBoard是iOS 5的新特征,旨在代替历史悠久的NIB/XIB(其实StoryBoard还是基于NIB/XIB的,不过开发人员已经无需直接跟NIB打交道了)。目前关于StoryBoard的文档并不多,苹果的iOS 5的开发...

晨曦之光
2012/05/28
757
0
ios使用xib自定义view

新建object-c类,从UIView继承 新建一个同名xib文件,修改File's Owner的Custom Class为新建的自定义view类名 将xib文件中的view链接到自定义view中 在xib文件里可以加入其它系统控件,并连接...

ZhengJumper
2014/02/20
19.7K
3
iOS开发之控制器的创建

1.怎么自己通过storyboard创建控制器,之前都是系统加载storyboard,帮我们创建好控制器。 通过UIStoryboard这个对象,就能加载storyboard文件注意:必须要有storyboard,创建UIStoryboard对象才...

shenhuniurou
2016/03/26
31
0
iOS一些代码的取巧写法总结(二)

一、在xib/storyboard里面设置view圆角半径 在xib/storyboard里面设置view圆角半径 神奇的IB_DESIGNABLE和IBInspectable(xib中设置圆角) 二、push pop 动画突然消失的解决方案 产生的原因是动...

朝雨晚风
2016/12/05
0
0
显示界面的切换/控制器的跳转

(自己使用过的介绍) 2016/1/22 0:26 关闭当前控制器 [self.navigationController popViewControllerAnimated:YES]; ---------------------------------------------------------------------......

阴雨音语
2016/01/22
79
0

没有更多内容

加载失败,请刷新页面

加载更多

Blockstack-2 :Blockstack ID注册

本篇文章主要记录Blockstack ID注册的流程; 在介绍注册流程之前,先简单的介绍一下Blockstack ID; 相对于传统互联网来说,Blockstack ID更像是统一的账号系统;即一个账号即可登录和授权所...

Riverzhou
今天
19
0
面试官问:平时碰到系统CPU飙高和频繁GC,你会怎么排查?

处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题。当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警。本文主要针对系统运...

Java高级架构师n
今天
33
0
面向对象编程

1、类和对象 类是对象的蓝图和模板,而对象是实例;即对象是具体的实例,类是一个抽象的模板 当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定...

huijue
今天
30
0
redis异常解决 :idea启动本地redis出现 jedis.exceptions.JedisDataException: NOAUTH Authentication required

第一次安装在本地redis服务,试试跑项目,结果却出现nested exception is redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required错误,真是让人头疼 先检查一...

青慕
今天
42
0
Spring 之 IoC 源码分析 (基于注解方式)

一、 IoC 理论 IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。 二、IoC方式 Spring为IoC提供了2种方式,一种是基于xml...

星爵22
今天
37
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部