Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended NibDesignable Version #54

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 139 additions & 46 deletions NibDesignable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@

import UIKit


/**
Protocol for `NibDesignable` pattern (related to `@IBDesignable`) for loading xib-based views for `UIView` subclasses in an `@IBDesignable`-compatible way. Views which are `NibDesignable` may typically be rendered in Interface Builder.

## See also

[NibDesignable](https://github.com/mbogh/NibDesignable) project on github.com (MIT License)

- authors: [@mbogh](https://github.com/mbogh), *et al*.
*/
public protocol NibDesignableProtocol: NSObjectProtocol {
/**
Identifies the view that will be the superview of the contents loaded from
Expand All @@ -31,165 +41,248 @@ public protocol NibDesignableProtocol: NSObjectProtocol {
- returns: Superview for Nib contents.
*/
var nibContainerView: UIView { get }
// MARK: - Nib loading

/**
Called to load the nib in setupNib().

- returns: UIView instance loaded from a nib file.
*/
func loadNib() -> UIView

/**
Called in the default implementation of loadNib(). Default is class name.

- returns: Name of a single view nib file.
*/
func nibName() -> String
var nibName: String { get }

/**
Called in the default implementation of loadNib(). Default is the bundle of the custom view class.

- returns: the bundle of the NibDesigable to look for the Nib for.
*/
var bundle: Bundle { get }

/**
Specifies which class should be responsible for loading the nib of this NibDesignable.
Defaults to the class that implements the NibDesignable protocol.
However, if subclasses of NibDesignable views (i.e. subclasses of subclasses of NibDesignable) don't want to
handle their own Nib but rely on that of their superclass, they should override this variable and return the
super class. This will make sure the superclass handles nib loading and will result in the same nib being used
for the sub class as was used by the superclass.

- returns: the class that handles the nib loading. This class needs to be implementing NibDesignableProtocol.
*/
var nibLoadingClass: AnyClass { get }
}

extension NibDesignableProtocol {
// MARK: - Nib loading

extension NibDesignableProtocol where Self: UIView {

/**
Called to load the nib in setupNib().

- returns: UIView instance loaded from a nib file.
*/
public func loadNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: self.nibName(), bundle: bundle)
return nib.instantiate(withOwner: self, options: nil)[0] as! UIView // swiftlint:disable:this force_cast
internal func loadNib() -> UIView {
let bundle = self.bundle
let nib = UINib(nibName: self.nibName, bundle: bundle)
let m_view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView // swiftlint:disable:this force_cast
return m_view
}

// MARK: - Nib loading

/**
Called in init(frame:) and init(aDecoder:) to load the nib and add it as a subview.
*/
fileprivate func setupNib() {
internal func setupNib() {
let view = self.loadNib()
self.nibContainerView.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
let bindings = ["view": view]
self.nibContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options:[], metrics:nil, views: bindings))
self.nibContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options:[], metrics:nil, views: bindings))
self.nibContainerView.preservesSuperviewLayoutMargins = true

if #available(iOS 11.0, *) {
// do nothing, because it works ok
} else {
// add the preservesSuperviewLayoutMargins workaround
// will be executed for anything < 11.0
view.preservesSuperviewLayoutMargins = true
}
}
}

extension UIView {
/// The nib container view of nib designable view.
/// Defaults to the view itself.
public var nibContainerView: UIView {
return self
}
/**
Called in the default implementation of loadNib(). Default is class name.

- returns: Name of a single view nib file.
*/
open func nibName() -> String {
return type(of: self).description().components(separatedBy: ".").last!
/// The name of the nib that the contents of this view is loaded from.
public var nibName: String {
return self.nibLoadingClass.description().components(separatedBy: ".").last!
}
/// The name of the bundle to look for the nib in. Defaults to the bundle
/// that contains the nibLoadingClass.
public var bundle: Bundle {
return Bundle(for: self.nibLoadingClass)
}

/// The class that is responsible for loading the nib. Defaults to the UIView's (sub)class itself.
public var nibLoadingClass: AnyClass {
return type(of: self)
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UIView`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignable: UIView, NibDesignableProtocol {

// MARK: - Initializer
/// :nodoc:
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}

// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UITableViewCell`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignableTableViewCell: UITableViewCell, NibDesignableProtocol {
public override var nibContainerView: UIView {

/// The nib container view of this TableView cell.
open var nibContainerView: UIView {
return self.contentView
}

// MARK: - Initializer
/// :nodoc:
override public init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.preservesSuperviewLayoutMargins = true
self.setupNib()
}

// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.preservesSuperviewLayoutMargins = true
self.setupNib()
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UIControl`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignableControl: UIControl, NibDesignableProtocol {

// MARK: - Initializer
/// :nodoc:
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}

// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UITableViewHeaderFooterView`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignableTableViewHeaderFooterView: UITableViewHeaderFooterView, NibDesignableProtocol {

public override var nibContainerView: UIView {
/// The nib container view of this TableView header footer view.
open var nibContainerView: UIView {
return self.contentView
}

// MARK: - Initializer
// MARK: - Initializer
/// :nodoc:
override public init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.setupNib()
}

// MARK: - NSCoding
// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
}
}

@IBDesignable
open class NibDesignableControl: UIControl, NibDesignableProtocol {

// MARK: - Initializer
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}

// MARK: - NSCoding
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UICollectionReusableView`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignableCollectionReusableView: UICollectionReusableView, NibDesignableProtocol {

// MARK: - Initializer
/// :nodoc:
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}

// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
}
}

/**
`NibDesignableProtocol`-compliant implementation of `UICollectionViewCell`

## See also
`NibDesignableProtocol`
*/
@IBDesignable
open class NibDesignableCollectionViewCell: UICollectionViewCell, NibDesignableProtocol {
public override var nibContainerView: UIView {

/// The nib container view of this collection view cell.
open var nibContainerView: UIView {
return self.contentView
}

// MARK: - Initializer
/// :nodoc:
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupNib()
}

// MARK: - NSCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupNib()
Expand Down