进行xib作业的时候常常会出现xib嵌套不显示的问题,如下面草图所示: MyView是Xib拖出来的,SubView也同样是,MyView中的左侧Class:输入SubView,在SubView中左侧输入SubView,这符合一贯的思路,但是运行起来不会显示你的SubView,这就出现了嵌套Xib不显示的问题,解决思路:
1.在SubView.Xib文件中,右侧导航栏Class:不填,保持原来的类型,在Placeholder--File's Owner下修改Class:SubView
2.在SubView.Swift文件中 ,SubView遵守一个自己封装的协议XibNestableView,如下:class SubView: XibNestableView {}, 初始化方法为:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
XibNestableView.Swift 拖入到工程文件中,文件内容为:
import UIKit
/// Xib 嵌套 Nib 所需继承的 View
class XibNestableView : UIView , NibLoadable {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if let view = UINib(nibName: String(describing: type(of: self)), bundle: nil).instantiate(withOwner: nil, options: nil)[0] as? UIView {
view.equal(to: self)
}
}
}
NibLoadable.Swift文件拖入工程中,内容为:
import UIKit
/// 标志符协议
protocol NameIdentifierable {
}
extension NameIdentifierable {
/// 将类型名称作为标识符字符串
static var identifier: String {
return String(describing: self)
}
}
/// 加载 Xib 协议
protocol NibLoadable: NameIdentifierable {
}
extension NibLoadable where Self : AnyObject {
/// 加载 Xib 中的 Nib 文件,Xib文件名称需与类型名称相同
static var nib: UINib {
return UINib(nibName: identifier, bundle: Bundle(for: self))
}
}
extension NibLoadable where Self: UIView {
/// 从 Nib 文件中加载 View
///
/// - Returns: 实现 NibLoadable 的 UIView
/// 例子: let view = UIView.loadFromNib()
static func loadFromNib() -> Self {
guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
fatalError("\(nib) Nib 文件的根视图需为 \(self) 类型")
}
return view
}
}
protocol NibOwnerLoadable : NameIdentifierable {
}
extension NibOwnerLoadable where Self : AnyObject {
/// 加载 Xib 中的 Nib 文件,Xib文件名称需与类型名称相同
static var nib: UINib {
return UINib(nibName: identifier, bundle: Bundle(for: self))
}
}
extension NibOwnerLoadable where Self: UIView {
/// 加载 File’s Owner 中的内容
/// 例子: required init?(coder aDecoder: NSCoder) {
/// super.init(coder: aDecoder)
/// self.loadNibContent()
/// }
func loadNibContent() {
let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing]
for case let view as UIView in Self.nib.instantiate(withOwner: self, options: nil) {
view.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(view)
NSLayoutConstraint.activate(layoutAttributes.map {
attribute in
NSLayoutConstraint(
item: view, attribute: attribute,
relatedBy: .equal,
toItem: self, attribute: attribute,
multiplier: 1, constant: 0.0
)
})
}
}
}
/// 加载 Storyboard 协议
protocol StoryboardLoadable {
/// 需要加在的 Storyboard 的名字
static var storyboardName: String? {
get }
}
extension StoryboardLoadable where Self : AnyObject, Self : NameIdentifierable {
/// 创建与 storyboardName 相同的 Storyboard, 若 storyboardName 为空则创建与当前类型名字相同的 Storyboard
static var storyboard: UIStoryboard {
return UIStoryboard(name: storyboardName ?? identifier, bundle: Bundle(for: self))
}
}
/// Storyboard 中的控制器加载协议
protocol StoryboardSceneLoadable : NameIdentifierable {
/// 需要提供目标 Storyboard, 可通过 StoryboardLoadable 协议创建
static var storyboard: UIStoryboard {
get }
}
extension StoryboardSceneLoadable {
/// ViewController 的标志符
static var sceneIdentifier: String {
return identifier
}
}
extension StoryboardSceneLoadable where Self: UIViewController {
//
/// 从 storyboard 中加载标志为 sceneIdentifier 的 ViewController
///
/// - Returns: 标志为 sceneIdentifier 的 ViewController
static func instantiate() -> Self {
let storyboard = Self.storyboard
let viewController = storyboard.instantiateViewController(withIdentifier: self.sceneIdentifier)
guard let typedViewController = viewController as? Self else {
fatalError("\(storyboard) 中的 '\(self.sceneIdentifier)'控制器不是 '\(self)' 类型")
}
return typedViewController
}
}
NibLoadable.Swift 协议的作用是将创建View由原来的方式:
let alertView = Bundle.main.loadNibNamed("BatchCloseAlertView", owner: vc, options: nil)?.first as! BatchCloseAlertView
修改为:
let alertView = BatchCloseAlertView.loadFromNib()