Как инициализировать/создать экземпляр класса UIView с XIB файлом в Swift
У меня есть класс под названием MyClass
, который является подклассом UIView
, который я хочу инициализировать с помощью файла XIB
. Я не уверен, как инициализировать этот класс с помощью xib файла с именем View.xib
class MyClass: UIView {
// what should I do here?
//init(coder aDecoder: NSCoder) {} ??
}
Ответы
Ответ 1
Я проверил этот код, и он прекрасно работает
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())
UDATE 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
}
Ответ 2
С 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
Сэм-решение уже велико, несмотря на то, что он не учитывает разные пакеты (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 в свой собственный класс.
Использование: просто подкласс вашего класса View из NibLoadingView.
Дополнительного кода больше не требуется.
Кредиты, в которых причитается кредит: Завершили это с незначительными изменениями от DenHeadless на GH. My Gist: https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8
Ответ 4
И это ответ Фредерика на 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
}
}
Ответ 5
Универсальный способ загрузки представления из xib:
Пример:
let myView = Bundle.loadView(fromNib: "MyView", withType: MyView.self)
Реализация:
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))
}
}
Ответ 6
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. Не беспокойтесь о владельце файла.
![Убедитесь, что Custom Class - MyClassView]()
Кроме того, убедитесь, что вы подключили розетку в MyClassView к метке:
![Выход для myLabel]()
Чтобы создать экземпляр:
let myClassView = MyClassView.createMyClassView()
myClassView.myLabel.text = "Hello World!"
Ответ 7
Swift 4
Здесь, в моем случае, я должен передать данные в это пользовательское представление, поэтому я создаю статическую функцию для создания экземпляра представления.
-
Создать расширение UIView
extension UIView {
class func initFromNib<T: UIView>() -> T {
return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T
}
}
-
Создать 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
}
}
-
Установите пользовательский класс для MyCustomView в файле .xib. Подключите розетку, если необходимо, как обычно. ![enter image description here]()
-
Инстанцирующий вид
let view = MyCustomView.instantiate(message: "Hello World.")
Ответ 8
Есть несколько фреймворков, которые реализуют один и тот же код, который упоминается несколько раз на этой странице.
Я публикую одну из таких платформ, LoadableViews.
И поскольку этот фреймворк уже используется почти во всех приложениях MLSDev, компании, над которой я работаю, он будет активно поддерживаться в обозримом будущем.
Просто размещать здесь для всех, кто заинтересован.
Ответ 9
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)
})
})
}