Customized UIView subclass from a xib file

Customized UIView subclass from a xib file


Do you need to discover ways to load a xib file to create a customized view object? Properly, this UIKit tutorial is only for you written in Swift.

I have already got a complete information about initializing views and controllers, however that one lacks a really particular case: making a customized view utilizing interface builder. 🤷‍♂️

Loading xib information

Utilizing the contents of a xib file is a reasonably rattling simple job to do. You need to use the next two strategies to load the contents (aka. the view hierarchy) of the file.

let view = UINib(
    nibName: "CustomView", 
    bundle: .major
).instantiate(
    withOwner: nil, 
    choices: nil
).first as! UIView

// does the identical as above
// let view = Bundle.major.loadNibNamed(
//    "CustomView", 
//    proprietor: nil, 
//    choices: nil
// )!.first as! UIView 

view.body = self.view.bounds
self.view.addSubview(view)

The snippet above will merely instantiate a view object from the xib file. You’ll be able to have a number of root objects within the view hierarchy, however this time let’s simply decide the primary one and use that. I assume that in 99% of the circumstances that is what you’ll want with a purpose to get your customized views. Additionally you may prolong the UIView object with any of the options above to create a generic view loader. Extra on that later… 😊

This methodology is fairly easy and low-cost, nonetheless there may be one little disadvantage. You’ll be able to’t get named pointers (retailers) for the views, however just for the foundation object. If you’re placing design parts into your display screen, that’s tremendous, but when it’s worthwhile to show dynamic information, you would possibly need to attain out for the underlying views as properly. 😃

Customized views with retailers & actions

So the correct option to load customized views from xib information goes one thing like this:

Inside your customized view object, you instantiate the xib file precisely the identical approach as I advised you proper up right here. 👆 The one distinction is that you just don’t want to make use of the article array returned by the strategies, however it’s important to join your view objects by the interface builder, utilizing the File’s Proprietor as a reference level, plus a customized container view outlet, that’ll include every thing you want. 🤨

// observe: view object is from my earlier tutorial, with autoresizing masks disabled
class CustomView: View {

    // that is going to be our container object
    @IBOutlet weak var containerView: UIView!

    // different regular retailers
    @IBOutlet weak var textLabel: UILabel!

    override func initialize() {
        tremendous.initialize()

        // first: load the view hierarchy to get correct retailers
        let title = String(describing: sort(of: self))
        let nib = UINib(nibName: title, bundle: .major)
        nib.instantiate(withOwner: self, choices: nil)

        // subsequent: append the container to our view
        self.addSubview(self.containerView)
        self.containerView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            self.containerView.topAnchor.constraint(equalTo: self.topAnchor),
            self.containerView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            self.containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            self.containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
        ])
    }
}

So the initialize methodology right here is simply loading the nib file with the proprietor of self. After the loading course of completed, your outlet pointers are going to be crammed with correct values from the xib file. There’s one last item that we have to do. Even the views from the xib file are “programmatically” linked to our customized view object, however visually they aren’t. So we’ve so as to add our container view into the view hierarchy. 🤐

IB

If you wish to use your customized view object, you simply should create a brand new occasion from it – inside a view controller – and at last be at liberty so as to add it as a subview!

One phrase about bounds, frames aka. springs and struts: fucking UGLY! That’s two phrases. They’re thought-about as a nasty apply, so please use auto format, I’ve a pleasant tutorial about anchors, they’re superb and studying them takes about quarter-hour. 😅

class ViewController: UIViewController {

    weak var customView: CustomView!

    override func loadView() {
        tremendous.loadView()

        let customView = CustomView()
        self.view.addSubview(customView)
        NSLayoutConstraint.activate([
            customView.topAnchor.constraint(equalTo: self.view.topAnchor),
            customView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            customView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            customView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        ])
        self.customView = customView
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.customView.textLabel.textual content = "Lorem ipsum"
    }
}

That’s it, now you will have a very working customized UIView object that hundreds a xib file with a purpose to use it’s contents. Wasn’t so dangerous, proper? 🤪

Yet another additional factor. In the event you don’t prefer to deal with views programmatically otherwise you merely don’t need to fiddle with the loadView methodology, simply take away it solely. Subsequent put the @IBOutlet key phrase proper earlier than your customized view class variable. Open your storyboard utilizing IB, then drag & drop a brand new UIView aspect to your controller and join the customized view outlet. It ought to work like magic. 💫

Storyboard

I promised retailers and actions within the heading of this part, so let’s speak a bit bit about IBActions. They work precisely the identical as you’d count on them with controllers. You’ll be able to merely hook-up a button to your customized view and delegate the motion to the customized view class. If you wish to ahead touches or particular actions to a controller, it is best to use the delegate sample or go along with a easy block. 😎

Possession and container views

It’s attainable to depart out all of the xib loading mechanism from the view occasion. We will create a set of extensions with a purpose to have a pleasant view loader with a customized view class from a xib file. This manner you don’t want a container view anymore, additionally the proprietor of the file may be unnoticed from the sport, it’s kind of the identical methodology as reusable cells for tables and collections created by Apple. 🍎

It’s best to know that going this manner you may’t use your default UIView init strategies programmatically anymore, as a result of the xib file will deal with the init course of. Additionally in case you are attempting to make use of this sort of customized views from a storyboard or xib file, you gained’t be capable to use your retailers, as a result of the correspondig xib of the view class gained’t be loaded. In any other case in case you are attempting to load it manyally you’ll run into an infinite loop and finally your app will crash like hell. 😈

import UIKit

extension UINib {
    func instantiate() -> Any? {
        return self.instantiate(withOwner: nil, choices: nil).first
    }
}

extension UIView {

    static var nib: UINib {
        return UINib(nibName: String(describing: self), bundle: nil)
    }

    static func instantiate(autolayout: Bool = true) -> Self {
        // generic helper perform
        func instantiateUsingNib<T: UIView>(autolayout: Bool) -> T {
            let view = self.nib.instantiate() as! T
            view.translatesAutoresizingMaskIntoConstraints = !autolayout
            return view
        }
        return instantiateUsingNib(autolayout: autolayout)
    }
}

class CustomView: UIView {

    @IBOutlet weak var textLabel: UILabel!
}

// utilization (inside a view controller for instance)
// let view = CustomView.instantiate()

Similar to with desk or assortment view cells this time it’s important to set your customized view class on the view object, as a substitute of the File’s Proprietor. You must join your retailers and principally you’re executed with every thing. 🤞

ownership

Any more it is best to ALWAYS use the instantiate methodology in your customized view object. The excellent news is that the perform is generic, returns the correct occasion sort and it’s extremely reusable. Oh, btw. I already talked about the dangerous information… 🤪

There’s additionally yet one more approach by overriding awakeAfter, however I might not depend on that resolution anymore. In a lot of the circumstances you may merely set the File’s Proprietor to your customized view, and go along with a container, that’s a secure guess. In case you have particular wants you would possibly want the second strategy, however please watch out with that. 😉

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 
rooshohttps://www.roosho.com
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here


Latest Articles

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog.