将XIB文件加载到UIView Swift

时间:2016-02-26 19:04:35

标签: swift

我正在尝试将XIB文件加载到UIView但我遇到了一些麻烦。我有所需的覆盖功能,但它们似乎崩溃了。说出这个错误,警告:

  

无法加载任何Objective-C类信息。这将   显着降低了可用类型信息的质量。

我想知道是否有人可以告诉我如何将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);  
    }
}

14 个答案:

答案 0 :(得分:39)

我在我们的一个项目中使用它,maby对你很有用

import UIKit

class RegisterPageView: UIView {

        class func instanceFromNib() -> RegisterPageView {
            return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
        }
}

答案 1 :(得分:18)

使用Swift 3.0

let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName", 
    owner: nil, 
    options: nil)?.first

答案 2 :(得分:13)

这是我的方法(用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 {}

现在我只需要从Xib(假设有一个)创建任何UIView子类,就像MyCustomView.instantiateFromXib()一样。请记住将您的Xib文件命名为UIView子类,并正确设置该Xib文件中主视图的类型。

只要SE-0068实施,就可以删除协议并将功能直接移至UIView扩展名。

只是注意:原始帖子使用具有嵌套视图的常用模式。恕我直言这是一个糟糕的模式,它不利用资源,只创建不必要的视图层次结构。

答案 3 :(得分:12)

改进了DevAndArtist UIView扩展程序

public extension UIView
{
    static func loadFromXib<T>(withOwner: Any? = nil, options: [AnyHashable : 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

答案 4 :(得分:7)

Swift 4.x

let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView

答案 5 :(得分:6)

swift 3

class YourClass:  UIView {
    class func instanceFromNib() -> YourClass {
        return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
    }
}

答案 6 :(得分:4)

在我的项目中,我实现了以下内容(非常类似于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

如果您的笔尖与您的类(MyView.xib)同名,则您需要设置:协议的默认实现查找与主包中的类同名的笔尖

当然,如果您的笔尖在另一个包中或者名称不同,您可以覆盖associatedNib并返回自己的笔尖。

答案 7 :(得分:3)

通常我使用以下方式加载自定义UIView所拥有的xib文件:

NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];

答案 8 :(得分:1)

let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView

答案 9 :(得分:0)

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)
    }

答案 10 :(得分:0)

我想分享这段代码,这需要我付出一些努力才能使其具有弹性。

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)
    }

}

您可以按照以下步骤使用它来创建名为类名(也称为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资源文件的所有者类设置为CustomView,并保留空白的自定义类类字段。

答案 11 :(得分:0)

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 = .....

答案 12 :(得分:0)

//**只需使用这个类作为视图的超类**

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

答案 13 :(得分:-1)

  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/