如何允许子 classes 使用父 class 的笔尖
How to allow subclasses to use parent class's nib
假设我有一个父视图 class,它至少包含 1 个 属性:
class BaseView : UIView {
@IBOutlet weak var myLabel: UILabel!
}
这个 class 有一个对应的 xib 文件,带有从 xib 到 myLabel 的出口连接 属性。
现在假设我们还有一些子 class 继承自此 class:
class ChildView : BaseView {
func setup() {}
}
ChildView 有一些自定义逻辑,但可以重复使用 BaseView 中的所有视图。它没有(或者我宁愿避免它有)自己对应的 xib 文件。
我希望能够做这样的事情:
let childView = Bundle.main.loadNibNamed(String(describing: BaseView.self), owner: nil, options:nil)?.first as! ChildViewA
但这不起作用。也没有:
let childView = ChildView()
Bundle.main.loadNibNamed(String(describing: BaseView.self owner: childView, options: nil)
有没有办法让子视图以类似的方式从其父视图的 xib 文件继承?
问题在于 nib 中的根视图是 BaseView
类型,因此 as! ChildViewA
失败。由于您无权访问 nib 加载器用于取消存档 xib 的 NSKeyedUnarchiver
,因此在取消存档期间没有简单的方法来替换您自己的 class。
这里有一个解决方法。
不要不要将BaseView
本身嵌入到xib中。相反,将 xib 中的顶级视图设为普通 UIView
,并将文件所有者自定义 class 设置为 BaseView
。然后删除与顶级视图的所有连接,并将它们设置在文件所有者上。还给 BaseView
一个 rootViewFromNib
插座,并将其连接到根视图。
然后,给 BaseView
一个加载其 nib 的初始化程序并将 rootViewFromNib
作为子视图添加到自身,其框架固定到 BaseView
自己的 bounds
.您可以使用自动调整大小来做到这一点。
最后,BaseView
应该是这样的:
class BaseView: UIView {
@IBOutlet var myLabel: UILabel!
// other outlets, etc.
@IBOutlet private var rootViewFromNib: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
Bundle(for: BaseView.self).loadNibNamed("BaseView", owner: self, options: nil)
rootViewFromNib.frame = bounds
rootViewFromNib.autoresizingMask = [.flexibleWidth, .flexibleHeight]
rootViewFromNib.translatesAutoresizingMaskIntoConstraints = true
addSubview(rootViewFromNib)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
和BaseView.xib
应该是这样的:
假设我有一个父视图 class,它至少包含 1 个 属性:
class BaseView : UIView {
@IBOutlet weak var myLabel: UILabel!
}
这个 class 有一个对应的 xib 文件,带有从 xib 到 myLabel 的出口连接 属性。
现在假设我们还有一些子 class 继承自此 class:
class ChildView : BaseView {
func setup() {}
}
ChildView 有一些自定义逻辑,但可以重复使用 BaseView 中的所有视图。它没有(或者我宁愿避免它有)自己对应的 xib 文件。
我希望能够做这样的事情:
let childView = Bundle.main.loadNibNamed(String(describing: BaseView.self), owner: nil, options:nil)?.first as! ChildViewA
但这不起作用。也没有:
let childView = ChildView()
Bundle.main.loadNibNamed(String(describing: BaseView.self owner: childView, options: nil)
有没有办法让子视图以类似的方式从其父视图的 xib 文件继承?
问题在于 nib 中的根视图是 BaseView
类型,因此 as! ChildViewA
失败。由于您无权访问 nib 加载器用于取消存档 xib 的 NSKeyedUnarchiver
,因此在取消存档期间没有简单的方法来替换您自己的 class。
这里有一个解决方法。
不要不要将BaseView
本身嵌入到xib中。相反,将 xib 中的顶级视图设为普通 UIView
,并将文件所有者自定义 class 设置为 BaseView
。然后删除与顶级视图的所有连接,并将它们设置在文件所有者上。还给 BaseView
一个 rootViewFromNib
插座,并将其连接到根视图。
然后,给 BaseView
一个加载其 nib 的初始化程序并将 rootViewFromNib
作为子视图添加到自身,其框架固定到 BaseView
自己的 bounds
.您可以使用自动调整大小来做到这一点。
最后,BaseView
应该是这样的:
class BaseView: UIView {
@IBOutlet var myLabel: UILabel!
// other outlets, etc.
@IBOutlet private var rootViewFromNib: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
Bundle(for: BaseView.self).loadNibNamed("BaseView", owner: self, options: nil)
rootViewFromNib.frame = bounds
rootViewFromNib.autoresizingMask = [.flexibleWidth, .flexibleHeight]
rootViewFromNib.translatesAutoresizingMaskIntoConstraints = true
addSubview(rootViewFromNib)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
和BaseView.xib
应该是这样的: