У меня есть класс, MyClass
который является подклассом UIView
, который я хочу инициализировать с помощью XIB
файла. Я не уверен, как инициализировать этот класс с помощью файла xib с именемView.xib
class MyClass: UIView {
// what should I do here?
//init(coder aDecoder: NSCoder) {} ??
}
Ответы:
Я протестировал этот код, и он отлично работает:
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())
ОБНОВЛЕНИЕ 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 }
источник
var view = MyClass.instanceFromNib()
&,self.view.addSubview(view)
а неvar view = MyClass.instanceFromNib
&self.view.addSubview(view())
. Просто небольшое предложение по улучшению ответа :)Решение Сэма уже отличное, несмотря на то, что оно не учитывает различные пакеты (на помощь приходит NSBundle: forClass) и требует ручной загрузки, то есть ввода кода.
Если вам нужна полная поддержка ваших выходов Xib, разных пакетов (используйте в рамках!) И получите хороший предварительный просмотр в раскадровке, попробуйте следующее:
// 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 } }
Используйте свой xib как обычно, т.е. подключите Outlets к File Owner и установите File Owner class в свой собственный класс.
Использование: просто создайте подкласс своего собственного класса View из NibLoadingView и установите имя класса на File's Owner в файле Xib.
Дополнительный код больше не требуется.
Кредиты, причитающиеся к оплате: Разветвлен с небольшими изменениями от DenHeadless на GH. Моя суть: https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8
источник
nibSetup
изinit?(coder:)
вызовет бесконечную рекурсию при встраиванииNibLoadingView
в XIB..clearColor()
- после загрузки его из раскадровки. Но он должен работать, если вы делаете это с помощью кода после его создания. В любом случае, как уже говорилось, еще более элегантный подход - это протокол на основе. Конечно, вот вам ссылка: github.com/AliSoftware/Reusable . Сейчас я использую аналогичный подход в отношении UITableViewCells (который я реализовал до того, как обнаружил этот действительно полезный проект). hth!Начиная с 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 } }
источник
var myView = nib.instantiate... as! myViewType
Swift 3
(XCode 8.0 beta 6) без проблем. Опечатка былаSwift 2
. Почему это должен быть другой ответ, если это хороший ответ, и пользователям, вероятно, понравится поиск, каковы изменения, когда они будут использовать XC8И это ответ Фредерика на Swift 3.0.
/* 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 } }
источник
Универсальный способ загрузки представления из 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)) } }
источник
Ответ 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. Не беспокойтесь о владельце файла.
Также убедитесь, что вы подключили розетку в MyClassView к метке:
Чтобы создать его:
let myClassView = MyClassView.createMyClassView() myClassView.myLabel.text = "Hello World!"
источник
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. При необходимости подключите розетку как обычно.
Реальный вид
let view = MyCustomView.instantiate(message: "Hello World.")
источник
Код ниже выполнит свою работу, если кто-то захочет программно загрузить пользовательское представление с 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)
источник
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) }) }) }
источник