在Storyboard中使用由xib定义的view

前言

在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/

转载于:https://my.oschina.net/wty21cn/blog/751944

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值