Nib Designable - Xcode Live Rendering with nibs made easy
In my previous post Xcode 6 Live Rendering From Nib, we ended up with CustomView
a UIView
subclass backed by a nib that is supported by Xcode Live Rendering.
import UIKit
@IBDesignable
class CustomView: UIView {
@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
private weak var proxyView: CustomView?
@IBInspectable public var title: String = "" {
didSet {
self.proxyView!.titleLabel.text = title
}
}
@IBInspectable public var avatarImage: UIImage = UIImage() {
didSet {
let size = self.avatarImage.size
let rect = CGRectMake(0, 0, size.width, size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
var path = UIBezierPath(ovalInRect: rect)
path.addClip()
self.avatarImage.drawInRect(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.proxyView!.avatarImageView.image = image
}
}
init(frame: CGRect) {
super.init(frame: frame)
var view = self.loadNib()
view.frame = self.bounds
view.autoresizingMask = .FlexibleWidth | .FlexibleHeight
self.proxyView = view
self.addSubview(self.proxyView)
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override func awakeAfterUsingCoder(aDecoder: NSCoder!) -> AnyObject! {
if self.subviews.count == 0 {
var view = self.loadNib()
view.setTranslatesAutoresizingMaskIntoConstraints(false)
let contraints = self.constraints()
self.removeConstraints(contraints)
view.addConstraints(contraints)
view.proxyView = view
return view
}
return self
}
private func loadNib() -> CustomView {
let bundle = NSBundle(forClass: self.dynamicType)
return bundle.loadNibNamed("CustomView", owner: nil, options: nil)[0] as CustomView
}
}
This works well for a single custom view, but who only got one custom view, so let me introduce Nib Designable.
Nib Designable is a single file which enables Live Rendering on its subclass’.
import UIKit
@IBDesignable
public class NibDesignable: UIView {
// MARK: - Initializer
override init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}
// MARK: - NSCoding
required public init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
self.setupNib()
}
// MARK: - Nib loading
/**
Called in init(frame:) and init(aDecoder:) to load the nib and add it as a subview.
*/
private func setupNib() {
var view = self.loadNib()
view.frame = self.bounds
view.autoresizingMask = .FlexibleWidth | .FlexibleHeight
self.addSubview(view)
}
/**
Called to load the nib in setupNib().
:returns: UIView instance loaded from a nib file.
*/
public func loadNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
return bundle.loadNibNamed(self.nibName(), owner: self, options: nil)[0] as UIView
}
/**
Called in the default implementation of loadNib(). Default is class name.
:returns: Name of a single view nib file.
*/
public func nibName() -> String {
return self.dynamicType.description().componentsSeparatedByString(".").last!
}
}
NibDesignable
is almost identical to CustomView
from my previous post.
I added nibName() -> String
to ease the usage.
For more details on Nib Designable, head over to the Github repository.
Update
I have updated Nib Designable so it is even easier to use.
No more proxyView
and you are no longer forced to subclass nibName()
, go check out the repository over at Github :)