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
How to initialize/instantiate a custom UIView class with a XIB file in Swift
提问by Stephen Fox
I have a class called MyClass
which is a subclass of UIView
, that I want to initialize with a XIB
file. 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 Self
rather 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。不要打扰文件的所有者。
Also, make sure that you connect the outlet in MyClassView to the label:
另外,请确保将 MyClassView 中的插座连接到标签:
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.
在我的情况下,我必须将数据传递到该自定义视图中,因此我创建了静态函数来实例化该视图。
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 } }
Create MyCustomView
let view = MyCustomView.instantiate(message: "Hello World.")
Set custom class to MyCustomView in .xib file. Connect outlet if necessary as usual.
Instantiate view
extension UIView { class func initFromNib<T: UIView>() -> T { return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T } }
创建 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 } }
创建我的自定义视图
let view = MyCustomView.instantiate(message: "Hello World.")
实例化视图
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) }) }) }