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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25513271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:03:37  来源:igfitidea点击:

How to initialize/instantiate a custom UIView class with a XIB file in Swift

iosswift

提问by Stephen Fox

I have a class called MyClasswhich is a subclass of UIView, that I want to initialize with a XIBfile. I am not sure how to initialize this class with the xib file called View.xib

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

class MyClass: UIView {

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

回答by Ezimet

I tested this code and it works great:

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

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

Initialise the view and use it like below:

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

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

OR

或者

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

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

更新 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
}

回答by Frederik A. Winkelsdorf

Sam's solution is already great, despite it doesn't take different bundles into account (NSBundle:forClass comes to the rescue) and requires manual loading, a.k.a typing code.

Sam 的解决方案已经很棒,尽管它没有考虑不同的包(NSBundle:forClass 来救援)并且需要手动加载,也就是输入代码。

If you want full support for your Xib Outlets, different Bundles (use in frameworks!) and get a nice preview in Storyboard try this:

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

// NibLoadingView.swift
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()
    }

    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
    }

}

Use your xib as usual, i.e. connect Outlets to File Owner and set File Owner class to your own class.

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

Usage: Just subclass your own View class from NibLoadingView & Set the class name to File's Ownerin the Xib file

用法:从NibLoadingView和类名设置只要继承自己的视图类文件的所有者在XIB文件

No additional code required anymore.

不再需要额外的代码。

Credits where credit's due: Forked this with minor changes from DenHeadless on GH. My Gist: https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8

信用到期的信用:从 GH 上的 DenHeadless 进行了微小的更改,将其分叉。我的要点:https: //gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8

回答by Sam

As of Swift 2.0, you can add a protocol extension. In my opinion, this is a better approach because the return type is Selfrather than UIView, so the caller doesn't need to cast to the view class.

从 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{
/*
 Usage:
 - make your CustomeView class and inherit from this one
 - in your Xib file make the file owner is your CustomeView class
 - *Important* the root view in your Xib file must be of type UIView
 - link all outlets to the file owner
 */
@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
    }
}
== "."}.map(String.init).last! let nib = UINib(nibName: nibName, bundle: nil) return nib.instantiateWithOwner(self, options: nil).first as! Self } }

回答by Mahmood S

And this is the answer of Frederik on Swift 3.0

这是 Frederik 在 Swift 3.0 上的回答

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

回答by Максим Мартынов

Universal way of loading view from xib:

从xib加载视图的通用方式:

Example:

例子:

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

Implementation:

执行:

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

回答by Jeremy

Swift 3 Answer:In my case, I wanted to have an outlet in my custom class that I could modify:

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

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

When in the .xib, make sure that the Custom Class field is MyClassView. Don't bother with the File's Owner.

在 .xib 中时,确保自定义类字段是 MyClassView。不要打扰文件的所有者。

Make sure Custom Class is MyClassView

确保自定义类是 MyClassView

Also, make sure that you connect the outlet in MyClassView to the label: Outlet for myLabel

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

To instantiate it:

要实例化它:

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

回答by mnemonic23

Swift 4

斯威夫特 4

Here in my case I have to pass data into that custom view, so I create static function to instantiate the view.

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

  1. Create UIView extension

    class MyCustomView: UIView {
    
        @IBOutlet weak var messageLabel: UILabel!
    
        static func instantiate(message: String) -> MyCustomView {
            let view: MyCustomView = initFromNib()
            view.messageLabel.text = message
            return view
        }
    }
    
  2. Create MyCustomView

    let view = MyCustomView.instantiate(message: "Hello World.")
    
  3. Set custom class to MyCustomView in .xib file. Connect outlet if necessary as usual. enter image description here

  4. Instantiate view

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

    class MyCustomView: UIView {
    
        @IBOutlet weak var messageLabel: UILabel!
    
        static func instantiate(message: String) -> MyCustomView {
            let view: MyCustomView = initFromNib()
            view.messageLabel.text = message
            return view
        }
    }
    
  2. 创建我的自定义视图

    let view = MyCustomView.instantiate(message: "Hello World.")
    
  3. 在 .xib 文件中将自定义类设置为 MyCustomView。如有必要,照常连接插座。 在此处输入图片说明

  4. 实例化视图

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

回答by Madan Kumawat

##代码##