I know how to use @IBDesignable with custom views. but is it possible to use IBDesignable for cells and render them in storyboard?
for example: i have a collectionViewController in storyboard, and added a uiCollectionCell and specified class as my customCellClass.
p.s: i know for using Xibs in collecionViews and tableViews we have to call method registerNib:forReuseIdentifer in code (and i am doing it). just wondered, is it possible to see it's rendered view in storyboard or not.
p.s2: i found this and it works perfectly with UIViews, but don't know how to make it work with CollectionCells and TableCells. :(
Yes. Here is what I found with Xcode 10.1 and iOS 12. Adding @IBDesignable
to the custom subclass of UICollectionViewCell
did work intermittently, but this works more reliably:
@IBDesignable
to a custom subclass of UIView
layoutSubviews()
, and define the appearance thereprepareForInterfaceBuilder()
UICollectionViewCell
in Interface BuilderMenu / Editor / Automatically Refresh Views
is checked, make some other change in Interface Builder)Example Class
@IBDesignable
class Avatar: UIView {
// Despite not being used for views designed in Interface Builder, must still be defined for custom UIView subclasses with @IBDesignable, or IB will report errors
override init(frame: CGRect) {
super.init(frame: frame)
}
// Used when a view is designed inside a view controller scene in Interface Builder and assigned to this custom UIView subclass
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width / 2
self.backgroundColor = UIColor.gray
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.backgroundColor = UIColor.blue
}
}
Yep. Here's how I did it.
First make sure the File Owner of NIB file is set to your custom cell class. Check this
Override the prepareForInterfaceBuilder
method and add the contentView
from NIB file in the contentView
of prototype cell. This is what it looks like.
// ArticleTableViewCell.swift
import UIKit
@IBDesignable
class ArticleTableViewCell: UITableViewCell {
@IBOutlet weak var authorLabel: UILabel!
@IBOutlet weak var authorImage: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var dateCreatedLabel: UILabel!
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
addNIBContentView(toView: contentView)
}
private func addNIBContentView() {
let view = loadContentViewFromNib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.addSubview(view)
}
private func loadContentViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
// Make sure your NIB file is named the same as this class, or else
// Put the name of NIB file manually (without the file extension)
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}
Editor > Refresh All Views
If it still does not show up. Just clear the build folder and refresh all views again.
Product > Clean Build Folder
I made a handy extension for myself to reuse the last 2 functions in all UITableView
s/UICollectionView
s
// ViewExtensions.swift
import UIKit
extension UIView {
func addNIBContentView(toView contentView: UIView? = nil) {
let view = loadContentViewFromNib()
// Use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
if let contentView = contentView {
contentView.addSubview(view)
} else {
addSubview(view)
}
}
private func loadContentViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
// Make sure your NIB file is named the same as it's class
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}
// ArticleTableViewCell.swift
import UIKit
@IBDesignable
class ArticleTableViewCell: UITableViewCell {
@IBOutlet weak var authorLabel: UILabel!
@IBOutlet weak var authorImage: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var dateCreatedLabel: UILabel!
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
addNIBContentView(toView: contentView)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With