Quantcast
Channel: Cloud in Touch
Viewing all articles
Browse latest Browse all 11

Designable xib in Xcode? Hell yeah!

$
0
0

I’d like to speak about liveness, it has been introduced in Xcode 6 and along with storyboard and interface preview is a great way to help you undestand how your application will look like without even launching on the simulator.
Watching the documentation I thought it was possible only by creating a subclass of UIView (or UIControl) programatically, while instead is possible to build our own UIView implementation and attach a xib file to it.
This is really helpful, for instance if you need to create a complex layout in a view building it with interface builder is a lot easier instead of coding each constraints.
How to do that?
1. Create a custom UIView subclass and a xib files, that we will name after our own class name: in our case MemeView. Inside the Meme View class remember to define it as designable, by adding the @IBDesignable attribute before the class declaration
2. Rember to set the File’s Owner in the xib with our custom UIView subclass in Indetity Inspector panel

Memeview custom class
3. In the xib file now we can build our interface, make constraints, create outlets, actions etc.

Meme view connection
4. We need to implement few methods to our custom class to open the xib once initialized

    weak var nibView: UIView!

    override convenience init(frame: CGRect) {
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        self.init(nibName: nibName)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }

    init(nibName: String) {
        super.init(frame: CGRectZero)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }

    func setUpConstraints() {
        ["V","H"].forEach { (quote) -> () in
            let format = String(format:"\(quote):|[nibView]|")
            addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: ["nibView" : nibView]))
        }
    }

    func loadNib(name: String) -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: name, bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

        return view
    }

5. In our custom class we can also define some inspectable properties to have full control over them from interface builder

 @IBInspectable var memeImage: UIImage = UIImage() {
        didSet {
            imageView.image = memeImage
        }
    }
    @IBInspectable var textColor: UIColor = UIColor.whiteColor() {
        didSet {
            label.textColor = textColor
        }
    }
    @IBInspectable var text: String = "" {
        didSet {
            label.text = text
        }
    }
    @IBInspectable var roundedCorners: Bool = false {
        didSet {
            if roundedCorners {
                layer.cornerRadius = 20.0
                clipsToBounds = true
            }
            else {
                layer.cornerRadius = 0.0
                clipsToBounds = false
            }
        }
    }

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var imageView: UIImageView!

In this case swift property observers are super helpful in detect property changes and apply them in real time to out interface.

As a note is worth to mention that not all the types of variable can be inspected (CGPoint, CGSize, CGRect, UIColor, NSRange, UIImage and numbers), for instance if you try to make a font property inspectable it will fail silently and it will not be displayed inside the attribute inspector.

To abstract a little more the xib loading process I created a class subclass of UIView that already takes care of loading “a same class name” xib.

Here are the results.

memeview grumphymeme view koala

If we need to fill with more information the view while it is displayed inside a storyboard or another xib, we can implement prepareForInterfaceBuilder(), this method will be executed only while opening the file in interface builder.

If you did everything I wrote but nothing is working, there is a way to debug a sigle view by adding breakpoints in its implementation.

debug view
You can download this little sample from dropbox.

The post Designable xib in Xcode? Hell yeah! appeared first on Cloud in Touch.


Viewing all articles
Browse latest Browse all 11

Trending Articles