在故事板中重用uiview xib

时间:2015-05-19 20:02:38

标签: uiview autolayout interface-builder uistoryboard xib

我通常喜欢在界面构建器中创建和设计我的uiviews。有时我需要在xib中创建一个可以在故事板中的多个视图控制器中重用的视图。

7 个答案:

答案 0 :(得分:123)

在故事板中重用并渲染xib。

使用Swift 2.2& S测试Xcode 7.3.1

1 ----创建一个名为'DesignableXibView'的新UIView

  • 文件>新>文件>来源> Cocoa Touch Class>的UIView

2 ----创建一个名为'DesignableXibView'

的匹配xib文件
  • 文件>新>文件>用户界面>图

3 ----设置xib

的文件所有者
  1. 选择xib
  2. 选择文件的所有者
  3. 在Identity Inspector中将自定义类设置为“DesignableXibView”。
  4. Setting a Xib's Owner to a Custom Class

    • 注意:不要在xib上设置视图的自定义类。只有文件所有者!

    4 ---- DesignableXibView的实现

    //  DesignableXibView.swift
    
    import UIKit
    
    @IBDesignable
    
    class DesignableXibView: UIView {
    
        var contentView : UIView?
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            xibSetup()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            xibSetup()
        }
    
        func xibSetup() {
            contentView = loadViewFromNib()
    
            // use bounds not frame or it'll be offset
            contentView!.frame = bounds
    
            // Make the view stretch with containing view
            contentView!.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
    
            // Adding custom subview on top of our view (over any custom drawing > see note below)
            addSubview(contentView!)
        }
    
        func loadViewFromNib() -> UIView! {
    
            let bundle = NSBundle(forClass: self.dynamicType)
            let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
            let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
    
            return view
        }
    
    }
    

    5 ----在故事板中测试可重复使用的视图

    1. 打开故事板
    2. 添加视图
    3. 设置该视图的自定义类
    4. 等一下...... BOOM !!
    5. Xib Rendering Inside a Storyboard View Controller

答案 1 :(得分:73)

NEW! updated answer with ability to render directly in the storyboard (and swift!)

适用于Xcode 6.3.1

创建一个名为“ReuseableView”的新UIView

  • 文件>新>文件>来源> Cocoa Touch Class>的UIView

创建一个名为“ReuseableView”的匹配xib文件

  • 文件>新>文件>用户界面>图

设置xib的文件所有者

  1. 选择xib
  2. 选择文件的所有者
  3. 在Identity Inspector中将自定义类设置为“ReusableView”。 enter image description here

    • 注意:不要在xib上设置视图的自定义类。只有文件所有者!
  4. 从ReuseableView.xib中的视图出口到ReuseableView.h接口

    1. 打开助理编辑器
    2. 控制+从视图拖动到界面
    3. enter image description here

      添加initWithCoder实现以加载视图并添加为子视图。

      - (id)initWithCoder:(NSCoder *)aDecoder{
          self = [super initWithCoder:aDecoder];
          if (self) {
      
              // 1. load the interface
              [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
              // 2. add as subview
              [self addSubview:self.view];
              // 3. allow for autolayout
              self.view.translatesAutoresizingMaskIntoConstraints = NO;
              // 4. add constraints to span entire view
              [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
              [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
      
          }
          return self;
      }
      

      enter image description here

      在故事板中测试可重复使用的视图

      1. 打开故事板
      2. 添加视图
      3. 设置该视图的自定义类
      4. enter image description here

        运行并观察! enter image description here

答案 2 :(得分:47)

  

Swift 3& 4更新为已接受的答案

<强> 1。创建一个名为&#39; DesignableXibView&#39;

的新UIView
  • 文件&gt;新&gt;文件&gt;来源&gt; Cocoa Touch Class&gt;的UIView

<强> 2。创建一个名为&#39; DesignableXibView&#39;

的匹配xib文件
  • 文件&gt;新&gt;文件&gt;用户界面&gt;图

第3。设置xib的文件所有者

选择&#34; DesignableXibView.xib&#34; &GT; &#34;文件所有者&#34; &GT; set&#34; Custom Class&#34;到&#39; DesignableXibView&#39;在Identity Inspector中。

  • 注意:不要在xib上设置视图的自定义类。只有 文件所有者!

<强> 4。 DesignableXibView的实施

    import UIKit

@IBDesignable

class DesignableXibView: UIView {

    var contentView : UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        xibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        xibSetup()
    }

    func xibSetup() {
        contentView = loadViewFromNib()

        // use bounds not frame or it'll be offset
        contentView.frame = bounds

        // Make the view stretch with containing view
        contentView.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]

        // Adding custom subview on top of our view 
        addSubview(contentView)
    }

    func loadViewFromNib() -> UIView! {

        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
        let view = nib.instantiate(withOwner: self, options: nil).first as! UIView

        return view
    }
} 

5在故事板中测试可重复使用的视图

  • 打开故事板

  • 添加视图

  • 设置该视图的自定义类

答案 3 :(得分:11)

swift 2中的initWithCoder函数,如果有人在翻译时遇到问题:

required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        UINib(nibName: String(self.dynamicType), bundle: NSBundle.mainBundle()).instantiateWithOwner(self, options: nil)
        self.addSubview(view)
        self.view.translatesAutoresizingMaskIntoConstraints = false
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterY , metrics: nil, views: ["view": self.view]))
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterX , metrics: nil, views: ["view": self.view]))
    }

答案 4 :(得分:1)

对于任何试图使接受的答案(通过@Garfbargle)适应Objective-C的人

仅将Swift转换为Objective-C不足以使其工作。我很难在Storyboard中进行实时渲染。

翻译完整个代码后,在设备(或模拟器)上运行时,视图加载良好,但Storyboard中的实时渲染不起作用。原因是我使用了[NSBundle mainBundle],而Interface Builder却没有访问mainBundle的权限。您必须使用[NSBundle bundleForClass:self.classForCoder]。 BOOM,实时渲染现已开始!

注意:如果您在使用自动版式配置时遇到问题,请尝试在Xib中禁用Safe Area Layout Guides

为方便起见,我将整个代码留在这里,以便您只需复制/粘贴(对于所有过程,请遵循original answer):

BottomBarView.h

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface BottomBarView : UIView

@end

BottomBarView.m

#import "BottomBarView.h"

@interface BottomBarView() {
    UIView *contentView;
}

@end


@implementation BottomBarView

-(id) initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self xibSetup];
    }
    return self;
}

-(id) initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self xibSetup];
    }
    return self;
}

-(void) xibSetup {
    contentView = [self loadViewFromNib];

    contentView.frame = self.bounds;

    contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    [self addSubview:contentView];
}

-(UIView*) loadViewFromNib {
    NSBundle *bundle = [NSBundle bundleForClass:self.classForCoder]; //this is the important line for view to render in IB
    UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:bundle];
    UIView *view = [nib instantiateWithOwner:self options:nil][0];

    return view;
}

@end

如果遇到一些问题,请告诉我,但是它几乎可以立即使用:)

答案 5 :(得分:0)

如果有人感兴趣,这是@Garfbargle的步骤4的 Xamarin.iOS 版本

public partial class CustomView : UIView
    {
        public ErrorView(IntPtr handle) : base(handle)
        {

        }

        [Export("awakeFromNib")]
        public override void AwakeFromNib()
        {
            var nibObjects = NSBundle.MainBundle.LoadNib("CustomView", this, null);
            var view = (UIView)Runtime.GetNSObject(nibObjects.ValueAt(0));
            view.Frame = Bounds;
            view.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;

            AddSubview(rootView);
        }
    }

答案 6 :(得分:0)

这是您一直想要的答案。您可以只创建CustomView类,并将其主实例包含在带有所有子视图和出口的xib中。然后,您可以将该类应用于情节提要或其他xib中的任何实例。

无需摆弄File的所有者,或将插座连接到代理,也无需以特殊方式修改xib,或将自定义视图的实例添加为其自身的子视图。

只需执行以下操作:

  1. 导入BFWControls框​​架
  2. 将您的超类从UIView更改为NibView(或从UITableViewCell更改为NibTableViewCell

就是这样!

它甚至可以与IBDesignable一起在设计时在情节提要中呈现您的自定义视图(包括xib的子视图)。

您可以在此处了解更多信息: https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155

您可以在此处获得开源的BFWControls框​​架: https://github.com/BareFeetWare/BFWControls

汤姆