将 XIB 文件加载到 UIView Swift
Loading a XIB file to a UIView Swift
我正在尝试将我的 XIB
文件加载到 UIView
中,但我遇到了一些问题。我有所需的覆盖功能,但它们似乎崩溃了。说这个错误,警告:
could not load any Objective-C class information. This will
significantly reduce the quality of type information available.
我想知道是否有人可以告诉我如何正确地将 XIB
文件加载到 UIView
import UIKit
class Widget: UIView {
let view = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
//call function
loadNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadNib()
//fatalError("init(coder:) has not been implemented")
}
func loadNib() {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "nib", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.addSubview(view);
}
}
通常我使用下面的方式来加载自定义的xib文件UIView
:
NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];
let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView
我在我们的一个项目中使用了它,可能对你有用
import UIKit
class RegisterPageView: UIView {
class func instanceFromNib() -> RegisterPageView {
return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
}
}
使用 Swift 3.0
let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName",
owner: nil,
options: nil)?.first
对于swift 3
class YourClass: UIView {
class func instanceFromNib() -> YourClass {
return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
}
}
在我的项目中,我实现了以下(与 Peter 的解决方案非常相似)
import UIKit
// MARK: - Protocol Declaration
public protocol InterfaceBuilderInstantiable
{
/// The UINib that contains the view
///
/// Defaults to the swift class name if not implemented
static var associatedNib : UINib { get }
}
// MARK: - Default Implementation
extension InterfaceBuilderInstantiable
{
/// Creates a new instance from the associated Xib
///
/// - Returns: A new instance of this object loaded from xib
static func instantiateFromInterfaceBuilder() -> Self
{
return associatedNib.instantiate(withOwner:nil, options: nil)[0] as! Self
}
static var associatedNib : UINib
{
let name = String(describing: self)
return UINib(nibName: name, bundle: Bundle.main)
}
}
要使用,您只需简单地实现协议:
class MyView: UIView, InterfaceBuilderInstantiable
{
// The rest
并且如果您的笔尖与您的 class (MyView.xib
) 同名,则您已设置:协议的默认实现查找与 class 在主包中。
当然,如果您的笔尖在另一个包中或具有不同的名称,您可以覆盖 associatedNib
和 return 您自己的笔尖。
这是我的方法(写在Swift 3.1):
protocol XibDesignable : class {}
extension XibDesignable where Self : UIView {
static func instantiateFromXib() -> Self {
let dynamicMetatype = Self.self
let bundle = Bundle(for: dynamicMetatype)
let nib = UINib(nibName: "\(dynamicMetatype)", bundle: bundle)
guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
fatalError("Could not load view from nib file.")
}
return view
}
}
extension UIView : XibDesignable {}
现在我可以像这样 MyCustomView.instantiateFromXib()
从 Xib(假设有一个)创建任何 UIView 子类。请记住将您的 Xib 文件命名为您的 UIView
子类并正确设置该 Xib 文件中主视图的类型。
一旦 SE-0068 实施,就可以删除协议并将功能直接移动到 UIView
扩展中。
请注意:原始 post 使用带有嵌套视图的常用模式。恕我直言,这是一个糟糕的模式,它不利用资源,只会创建不必要的视图层次结构。
改进了 UIView 扩展
public extension UIView
{
static func loadFromXib<T>(withOwner: Any? = nil, options: [UINib.OptionsKey : Any]? = nil) -> T where T: UIView
{
let bundle = Bundle(for: self)
let nib = UINib(nibName: "\(self)", bundle: bundle)
guard let view = nib.instantiate(withOwner: withOwner, options: options).first as? T else {
fatalError("Could not load view from nib file.")
}
return view
}
}
用法
let view = CustomView.loadFromXib()
let view = CustomView.loadFromXib(withOwner: self)
let view = CustomView.loadFromXib(withOwner: self, options: [UINibExternalObjects: objects])
External Objects discussion
Swift 4.x
let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView
func configureNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomUIView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
并将本教程用于 xib 的自定义视图...
https://developerfly.com/custom-view-use-xib-swift/
Swift 4.x
我终于做到了
这不在 customView 本身中。我把代码放在 ViewController 加载 customView 的地方。
import UIKit
class StartMenuViewController: UIViewController {
@IBOutlet weak var customView: CustomView!
override func viewDidLoad() {
super.viewDidLoad()
let myView = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)![0] as! UIView
customView .addSubview(myView)
}
我想分享这段代码,它需要我付出一些努力才能使其具有弹性。
import Foundation
protocol Nib {
func registerNib()
}
extension Nib where Self : UIView {
func registerNib() {
guard let nibName = type(of: self).description().components(separatedBy: ".").last else { return }
// ** Check if resource is used in Interface Builder first to avoid crash during compile
#if !TARGET_INTERFACE_BUILDER
let bundle = Bundle(for: type(of: self))
guard let _ = bundle.path(forResource: nibName, ofType: "nib")
else { fatalError("can't find \(nibName) xib resource in current bundle") }
#endif
guard let view = Bundle(for: type(of: self)).loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView
else { return }
// ** Another way to write it but do not work if xib is bundled with framework
//guard let view = UINib(nibName: nibName, bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView
// else { return }
view.frame = bounds
addSubview(view)
}
}
您可以使用它创建一个名为 class 名称(又名 CustomView.xib)
的 xib 资源文件
import UIKit
class CustomView: UIView, Nib {
override init(frame: CGRect) {
super.init(frame: frame)
postInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
postInit()
}
func postInit() {
registerNib()
}
}
不要忘记将 xib 资源文件的所有者 class 设置为 CustomView 并将自定义 class class 字段留空。
Swift 5.x
let loadMusicView = Bundle.main.loadNibNamed("MusicView", owner: nil, options: nil)![0] as? MusicView
loadMusicView?.frame = controlsMainView.bounds
loadMusicView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controlsMainView.addSubview(loadMusicView!)
//if you have variables in your .xib file access those variables like this
loadMusicView.yourVariableName = .....
//**只需将此 class 用作视图的超级 class **
import UIKit
class ViewWithXib: UIView {
func initUI() {}
private func xibSetup() {
let view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
initUI()
}
private func loadViewFromNib() -> UIView {
let thisName = String(describing: type(of: self))
let view = Bundle(for: self.classForCoder).loadNibNamed(thisName, owner: self, options: nil)?.first as! UIView
return view
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
}
// 用法
class HeaderView: ViewWithXib {
}
let header = HeaderView() // No need to load the view from nib, It will work
我正在尝试将我的 XIB
文件加载到 UIView
中,但我遇到了一些问题。我有所需的覆盖功能,但它们似乎崩溃了。说这个错误,警告:
could not load any Objective-C class information. This will significantly reduce the quality of type information available.
我想知道是否有人可以告诉我如何正确地将 XIB
文件加载到 UIView
import UIKit
class Widget: UIView {
let view = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
//call function
loadNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadNib()
//fatalError("init(coder:) has not been implemented")
}
func loadNib() {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "nib", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.addSubview(view);
}
}
通常我使用下面的方式来加载自定义的xib文件UIView
:
NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];
let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView
我在我们的一个项目中使用了它,可能对你有用
import UIKit
class RegisterPageView: UIView {
class func instanceFromNib() -> RegisterPageView {
return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
}
}
使用 Swift 3.0
let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName",
owner: nil,
options: nil)?.first
对于swift 3
class YourClass: UIView {
class func instanceFromNib() -> YourClass {
return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
}
}
在我的项目中,我实现了以下(与 Peter 的解决方案非常相似)
import UIKit
// MARK: - Protocol Declaration
public protocol InterfaceBuilderInstantiable
{
/// The UINib that contains the view
///
/// Defaults to the swift class name if not implemented
static var associatedNib : UINib { get }
}
// MARK: - Default Implementation
extension InterfaceBuilderInstantiable
{
/// Creates a new instance from the associated Xib
///
/// - Returns: A new instance of this object loaded from xib
static func instantiateFromInterfaceBuilder() -> Self
{
return associatedNib.instantiate(withOwner:nil, options: nil)[0] as! Self
}
static var associatedNib : UINib
{
let name = String(describing: self)
return UINib(nibName: name, bundle: Bundle.main)
}
}
要使用,您只需简单地实现协议:
class MyView: UIView, InterfaceBuilderInstantiable
{
// The rest
并且如果您的笔尖与您的 class (MyView.xib
) 同名,则您已设置:协议的默认实现查找与 class 在主包中。
当然,如果您的笔尖在另一个包中或具有不同的名称,您可以覆盖 associatedNib
和 return 您自己的笔尖。
这是我的方法(写在Swift 3.1):
protocol XibDesignable : class {}
extension XibDesignable where Self : UIView {
static func instantiateFromXib() -> Self {
let dynamicMetatype = Self.self
let bundle = Bundle(for: dynamicMetatype)
let nib = UINib(nibName: "\(dynamicMetatype)", bundle: bundle)
guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
fatalError("Could not load view from nib file.")
}
return view
}
}
extension UIView : XibDesignable {}
现在我可以像这样 MyCustomView.instantiateFromXib()
从 Xib(假设有一个)创建任何 UIView 子类。请记住将您的 Xib 文件命名为您的 UIView
子类并正确设置该 Xib 文件中主视图的类型。
一旦 SE-0068 实施,就可以删除协议并将功能直接移动到 UIView
扩展中。
请注意:原始 post 使用带有嵌套视图的常用模式。恕我直言,这是一个糟糕的模式,它不利用资源,只会创建不必要的视图层次结构。
改进了
public extension UIView
{
static func loadFromXib<T>(withOwner: Any? = nil, options: [UINib.OptionsKey : Any]? = nil) -> T where T: UIView
{
let bundle = Bundle(for: self)
let nib = UINib(nibName: "\(self)", bundle: bundle)
guard let view = nib.instantiate(withOwner: withOwner, options: options).first as? T else {
fatalError("Could not load view from nib file.")
}
return view
}
}
用法
let view = CustomView.loadFromXib()
let view = CustomView.loadFromXib(withOwner: self)
let view = CustomView.loadFromXib(withOwner: self, options: [UINibExternalObjects: objects])
External Objects discussion
Swift 4.x
let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView
func configureNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomUIView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
并将本教程用于 xib 的自定义视图... https://developerfly.com/custom-view-use-xib-swift/
Swift 4.x
我终于做到了 这不在 customView 本身中。我把代码放在 ViewController 加载 customView 的地方。
import UIKit
class StartMenuViewController: UIViewController {
@IBOutlet weak var customView: CustomView!
override func viewDidLoad() {
super.viewDidLoad()
let myView = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)![0] as! UIView
customView .addSubview(myView)
}
我想分享这段代码,它需要我付出一些努力才能使其具有弹性。
import Foundation
protocol Nib {
func registerNib()
}
extension Nib where Self : UIView {
func registerNib() {
guard let nibName = type(of: self).description().components(separatedBy: ".").last else { return }
// ** Check if resource is used in Interface Builder first to avoid crash during compile
#if !TARGET_INTERFACE_BUILDER
let bundle = Bundle(for: type(of: self))
guard let _ = bundle.path(forResource: nibName, ofType: "nib")
else { fatalError("can't find \(nibName) xib resource in current bundle") }
#endif
guard let view = Bundle(for: type(of: self)).loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView
else { return }
// ** Another way to write it but do not work if xib is bundled with framework
//guard let view = UINib(nibName: nibName, bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView
// else { return }
view.frame = bounds
addSubview(view)
}
}
您可以使用它创建一个名为 class 名称(又名 CustomView.xib)
的 xib 资源文件import UIKit
class CustomView: UIView, Nib {
override init(frame: CGRect) {
super.init(frame: frame)
postInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
postInit()
}
func postInit() {
registerNib()
}
}
不要忘记将 xib 资源文件的所有者 class 设置为 CustomView 并将自定义 class class 字段留空。
Swift 5.x
let loadMusicView = Bundle.main.loadNibNamed("MusicView", owner: nil, options: nil)![0] as? MusicView
loadMusicView?.frame = controlsMainView.bounds
loadMusicView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controlsMainView.addSubview(loadMusicView!)
//if you have variables in your .xib file access those variables like this
loadMusicView.yourVariableName = .....
//**只需将此 class 用作视图的超级 class **
import UIKit
class ViewWithXib: UIView {
func initUI() {}
private func xibSetup() {
let view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
initUI()
}
private func loadViewFromNib() -> UIView {
let thisName = String(describing: type(of: self))
let view = Bundle(for: self.classForCoder).loadNibNamed(thisName, owner: self, options: nil)?.first as! UIView
return view
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
}
// 用法
class HeaderView: ViewWithXib {
}
let header = HeaderView() // No need to load the view from nib, It will work