如何在Swift中使用XIB文件初始化/实例化自定义UIView类

时间:2014-08-26 18:57:02

标签: ios swift

我有一个名为MyClass的类,它是UIView的子类,我想用XIB文件进行初始化。我不确定如何使用名为View.xib

的xib文件初始化此类
class MyClass: UIView {

    // what should I do here? 
    //init(coder aDecoder: NSCoder) {} ?? 
}

11 个答案:

答案 0 :(得分:236)

我测试了这段代码,效果很好

class MyClass: UIView {

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

}

初始化视图并使用如下所示

    var view = MyClass.instanceFromNib()
    self.view.addSubview(view)

    var view = MyClass.instanceFromNib
    self.view.addSubview(view())

UPDATE Swift> = 3.x& Swift> = 4.x

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

答案 1 :(得分:77)

Sam的解决方案已经很好了,尽管它没有考虑不同的捆绑(NSBundle:forClass来救援)并且需要手动加载,a.k.a打字代码。

如果你想完全支持你的Xib Outlets,不同的Bundles(在框架中使用!)并在Storyboard中获得一个很好的预览,试试这个:

// NibLoadingView.swift
import UIKit

// Usage: Subclass your UIView from NibLoadView to automatically load a xib with the same name as your class

@IBDesignable
class NibLoadingView: UIView {

    @IBOutlet weak var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        nibSetup()
    }

    private func nibSetup() {
        backgroundColor = .clearColor()

        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        view.translatesAutoresizingMaskIntoConstraints = true

        addSubview(view)
    }

    private func loadViewFromNib() -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
        let nibView = nib.instantiateWithOwner(self, options: nil).first as! UIView

        return nibView
    }

}

像往常一样使用你的xib,即将Outlets连接到File Owner并将File Owner类设置为你自己的类。

用法:只需从NibLoadingView继承自己的View类。

不再需要其他代码。

信用额到期的信用:在DenHeadless对GH的微小变化中加以分析。我的要点:https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8

答案 2 :(得分:73)

从Swift 2.0开始,您可以添加协议扩展。在我看来,这是一种更好的方法,因为返回类型是Self而不是UIView,因此调用者不需要强制转换为视图类。

import UIKit

protocol UIViewLoading {}
extension UIView : UIViewLoading {}

extension UIViewLoading where Self : UIView {

  // note that this method returns an instance of type `Self`, rather than UIView
  static func loadFromNib() -> Self {
    let nibName = "\(self)".characters.split{$0 == "."}.map(String.init).last!
    let nib = UINib(nibName: nibName, bundle: nil)
    return nib.instantiateWithOwner(self, options: nil).first as! Self
  }

}

答案 3 :(得分:35)

这就是Frederik在Swift 3.0上的答案

@IBDesignable
class NibLoadingView: UIView {

    @IBOutlet weak var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        nibSetup()
    }

    private func nibSetup() {
        backgroundColor = .clear

        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.translatesAutoresizingMaskIntoConstraints = true

        addSubview(view)
    }

    private func loadViewFromNib() -> UIView {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
        let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView

        return nibView
    }
}

答案 4 :(得分:30)

Universal way of loading view from xib:

Example:

let myView = Bundle.loadView(fromNib: "MyView", withType: MyView.self)

Implementation:

extension Bundle {

    static func loadView<T>(fromNib name: String, withType type: T.Type) -> T {
        if let view = Bundle.main.loadNibNamed(name, owner: nil, options: nil)?.first as? T {
            return view
        }

        fatalError("Could not load view with type " + String(describing: type))
    }
}

答案 5 :(得分:26)

Swift 3答案:就我而言,我想在我的自定义课程中设置一个我可以修改的插座:

class MyClassView: UIView {
    @IBOutlet weak var myLabel: UILabel!

    class func createMyClassView() -> MyClass {
        let myClassNib = UINib(nibName: "MyClass", bundle: nil)
        return myClassNib.instantiate(withOwner: nil, options: nil)[0] as! MyClassView
    }
}

在.xib中,确保Custom Class字段为MyClassView。不要为File的所有者烦恼。

Make sure Custom Class is MyClassView

另外,请确保将MyClassView中的插座连接到标签: Outlet for myLabel

要实例化它:

let myClassView = MyClassView.createMyClassView()
myClassView.myLabel.text = "Hello World!"

答案 6 :(得分:14)

快捷键4

在这种情况下,我必须将数据传递到该自定义视图中,因此我创建了静态函数来实例化该视图。

  1. 创建UIView扩展

    extension UIView {
        class func initFromNib<T: UIView>() -> T {
            return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T
        }
    }
    
  2. 创建MyCustomView

    class MyCustomView: UIView {
    
        @IBOutlet weak var messageLabel: UILabel!
    
        static func instantiate(message: String) -> MyCustomView {
            let view: MyCustomView = initFromNib()
            view.messageLabel.text = message
            return view
        }
    }
    
  3. 在.xib文件中将自定义类设置为MyCustomView。照常连接插座。 enter image description here

  4. 实例化视图

    let view = MyCustomView.instantiate(message: "Hello World.")
    

答案 7 :(得分:3)

有一些框架实现了在此页面上多次提到的相同代码。

我正在发布其中一个框架LoadableViews

由于这个框架已经在MLSDev的几乎所有应用程序中使用,我正在研究的公司,它将在可预见的未来得到积极支持。

只需在此处发帖给任何感兴趣的人。

答案 8 :(得分:2)

Swift 5.2

创建一个名为 import Foundation import UIKit /* Usage: - Subclass your UIView from NibLoadView to automatically load an Xib with the same name as your class - Set the class name to File's Owner in the Xib file */ @IBDesignable class NibLoadingView: UIView { @IBOutlet weak var view: UIView! override init(frame: CGRect) { super.init(frame: frame) nibSetup() } override func awakeFromNib() { super.awakeFromNib() nibSetup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) nibSetup() } private func nibSetup() { view = loadViewFromNib() view.frame = bounds view.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.translatesAutoresizingMaskIntoConstraints = true addSubview(view) } private func loadViewFromNib() -> UIView { let bundle = Bundle(for: type(of: self)) let nib = UINib(nibName: type(of: self).description().replacingOccurrences(of: "REPLACEME.", with: ""), bundle: bundle) let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView return nibView } } 的类,内容如下:

REPLACEME

在上面的代码中找到 NibLoadingView 并将其替换为您的项目名称。

现在创建一个 XIB 和 UIView 类对,将 XIB 的所有者设置为 UIView 类和子类 ExampleView()

您现在可以像 ExampleView(frame: CGRect)、{{1}} 等一样初始化类

基于Frederik's answer

答案 9 :(得分:1)

如果有人想以编程方式使用XIB加载自定义视图,则下面的代码将起作用。

let customView = UINib(nibName:"CustomView",bundle:.main).instantiate(withOwner: nil, options: nil).first as! UIView
customView.frame = self.view.bounds
self.view.addSubview(customView)

答案 10 :(得分:-2)

override func draw(_ rect: CGRect) 
{
    AlertView.layer.cornerRadius = 4
    AlertView.clipsToBounds = true

    btnOk.layer.cornerRadius = 4
    btnOk.clipsToBounds = true   
}

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

@IBAction func okBtnDidClicked(_ sender: Any) {

    removeAlertViewFromWindow()

    UIView.animate(withDuration: 0.4, delay: 0.0, options: .allowAnimatedContent, animations: {() -> Void in
        self.AlertView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

    }, completion: {(finished: Bool) -> Void in
        self.AlertView.transform = CGAffineTransform.identity
        self.AlertView.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
        self.AlertView.isHidden = true
        self.AlertView.alpha = 0.0

        self.alpha = 0.5
    })
}


func removeAlertViewFromWindow()
{
    for subview  in (appDel.window?.subviews)! {
        if subview.tag == 500500{
            subview.removeFromSuperview()
        }
    }
}


public func openAlertView(title:String , string : String ){

    lblTital.text  = title
    txtView.text  = string

    self.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
    appDel.window!.addSubview(self)


    AlertView.alpha = 1.0
    AlertView.isHidden = false

    UIView.animate(withDuration: 0.2, animations: {() -> Void in
        self.alpha = 1.0
    })
    AlertView.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)

    UIView.animate(withDuration: 0.3, delay: 0.2, options: .allowAnimatedContent, animations: {() -> Void in
        self.AlertView.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)

    }, completion: {(finished: Bool) -> Void in
        UIView.animate(withDuration: 0.2, animations: {() -> Void in
            self.AlertView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)

        })
    })


}