I'm attempting to configure a custom UIView
in interface builder and get the view to render. Every time I attempt to do this with a custom Xib, I can get the xib to look fine in interface builder, but the moment I attempt to drop my MyCustomView
into a UIVewController
in interface builder, I get all sorts of compiler errors.
Every tutorial I've looked at goes something like this: "Just add @IBDesignable
in front of your class declaration and put @IBInspectable
in front of your vars and then watch the magic happen" (example: WWDC 2015 video). Or it's in Objective-C, or it's a 30 minute video in Aramaic with Chinese subtitles, etc.
My end objective is to be able to drag a UIView in, assign my custom class in identity inspector and have the contents of xib fill the UIView I dragged in and be able to tweak @IBInspectable
properties.
Where I've looked for answers:
SO Post: @IBDesignable crashing agent
Errors I get:
Base.lproj/Main.storyboard: error: IB Designables: Failed to render and update auto layout status for PlaylistViewController (o1G-QR-OwX): The agent crashed
Base.lproj/Main.storyboard: error: IB Designables: Failed to update auto layout status: The agent crashed
Identity Inspector for my CurrentlyPlayingView
:
Storyboard of my view after the I get the aforementioned errors:
The view that I'm trying to get to appear at the bottom of the above storyboard:
My code:
import UIKit
@IBDesignable class CurrentlyPlayingView: UIView {
var view = UIView()
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subtitleLabel: UILabel!
@IBOutlet weak var progressSlider: UISlider!
// IBInspectable attributes
@IBInspectable public var titleLabelColor: UIColor = .black {
didSet {
self.titleLabel.textColor = titleLabelColor
}
}
@IBInspectable public var subtitleLabelColor: UIColor = .black {
didSet {
self.subtitleLabel.textColor = subtitleLabelColor
}
}
@IBInspectable public var sliderMinColor: UIColor = .blue {
didSet {
self.progressSlider.minimumTrackTintColor = sliderMinColor
}
}
@IBInspectable public var sliderMaxColor: UIColor = .red {
didSet {
self.progressSlider.maximumTrackTintColor = sliderMaxColor
}
}
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
initialConfig()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
initialConfig()
}
private func initialConfig() {
self.titleLabel.textColor = titleLabelColor
self.subtitleLabel.textColor = subtitleLabelColor
self.progressSlider.minimumTrackTintColor = sliderMinColor
self.progressSlider.maximumTrackTintColor = sliderMaxColor
}
// MARK: - Nib handlers
private func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
}
private func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CurrentlyPlayingView", bundle: bundle)
// Assumes UIView is top level and only object in CustomView.xib file
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}
If you've made it this far, thank you for reading. If you see what I'm missing, I welcome your suggestions.
I think this is because you are missing your prepareForInterfaceBuilder
function.
Override this function something like this.
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
//setup your view with the settings
}
Addendum by OP:
Once you drag a UIView
out to YourViewController
and set its Custom Class in Identity Inspector to YourCustomView
, ensure "Inherit from Target" is ticked (as of Xcode 8.x).