Add Subview from a Xib or Another Scene with Storyboard

Add subview from a xib or another scene with storyboard

I figured out a way to do it.
Described as following:

  1. Create a .xib file. For example: MyView.xib
  2. Create a objective-c class. For example: MyViewClass.h and MyViewClass.m
  3. Set the .xib File's Owner to the class.
  4. Add a UIView element on the storyboard and set the custom class to the objective-c class name (MyViewClass).
  5. The key-point is to override the initWithCoder method in the object-c class.

    - (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
    [self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil] objectAtIndex:0]];
    }
    return self;
    }

The idea is the custom class is loaded by the storyboard and initWithCode will be called.
The index 0 is the root view in the .xib interface builder.

It's kind of tricky but it works.

How to embed a custom view xib in a storyboard scene?

You're almost there. You need to override initWithCoder in your custom class you assigned the view to.

- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"ViewYouCreated" owner:self options:nil] objectAtIndex:0]];
}
return self; }

Once that's done the StoryBoard will know to load the xib inside that UIView.

Here's a more detailed explanation:

This is how your UIViewController looks like on your story board:
Sample Image

The blue space is basically a UIView that will "hold" your xib.

This is your xib:

Sample Image

There's an Action connected to a button on it that will print some text.

and this is the final result:

Sample Image

The difference between the first clickMe and the second is that the first was added to the UIViewController using the StoryBoard. The second was added using code.

Load view from an external xib file in storyboard

My full example is here, but I will provide a summary below.

Layout

Add a .swift and .xib file each with the same name to your project. The .xib file contains your custom view layout (using auto layout constraints preferably).

Make the swift file the xib file's owner.

Sample Image
Code

Add the following code to the .swift file and hook up the outlets and actions from the .xib file.

import UIKit
class ResuableCustomView: UIView {

let nibName = "ReusableCustomView"
var contentView: UIView?

@IBOutlet weak var label: UILabel!
@IBAction func buttonTap(_ sender: UIButton) {
label.text = "Hi"
}

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

guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
contentView = view
}

func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}

Use it

Use your custom view anywhere in your storyboard. Just add a UIView and set the class name to your custom class name.

Sample Image

Add a subview to a custom class UIViewController that loads from nib, in Storyboard

I think it's one of those "if you need to work around it, you're probably doing it wrong" scenarios you so often hit in iOS development. :-) Really, if you want the functionality the JSQMessagesViewController provides, you shouldn't need to add additional views. But if you must add views, the "right" way to do it is to add them as subviews of whatever self.view is after you call super in viewDidLoad. If you don't want to construct views programmatically, you can put them in a separate nib (instead of the storyboard) and manually load them.

(Note: this is assuming viewDidLoad is getting called. If it isn't, you might need to hook into some other method.)

Reuse a uiview xib in storyboard

Reuse and render a xib in a storyboard.

Tested with Swift 2.2 & Xcode 7.3.1

1 ---- Create a new UIView named 'DesignableXibView'

  • File > New > File > Source > Cocoa Touch Class > UIView

2 ---- Create a matching xib file named 'DesignableXibView'

  • File > New > File > User Interface > View

3 ---- Set the file owner of the of the xib

  1. select the xib
  2. select file's owner
  3. set custom class to 'DesignableXibView' in the Identity Inspector.

Setting a Xib's Owner to a Custom Class

  • Note: Do not set the custom class of the view on the xib. Only the File Owner!

4 ---- DesignableXibView's Implementation

//  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 ---- Test your reuseable view in a storyboard

  1. Open your storyboard
  2. Add a view
  3. Set that view's Custom Class
  4. wait a sec ... BOOM!!

Xib Rendering Inside a Storyboard View Controller



Related Topics



Leave a reply



Submit