J'ai une classe appelée MyClass
, qui est une sous-classe de UIView
, que je souhaite initialiser avec un fichier XIB
. Je ne sais pas comment initialiser cette classe avec le fichier xib appelé View.xib
class MyClass: UIView {
// what should I do here?
//init(coder aDecoder: NSCoder) {} ??
}
J'ai testé ce code et cela fonctionne très bien
class MyClass: UIView {
class func instanceFromNib() -> UIView {
return UINib(nibName: "nib file name", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as UIView
}
}
Initialiser la vue et l'utiliser comme ci-dessous
var view = MyClass.instanceFromNib()
self.view.addSubview(view)
OU
var view = MyClass.instanceFromNib
self.view.addSubview(view())
PDATE 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
}
La solution de Sam est déjà excellente, même si elle ne prend pas en compte différents bundles (NSBundle: forClass vient à la rescousse) et nécessite un chargement manuel, du code de frappe a.k.a.
Si vous souhaitez une prise en charge complète de vos prises Xib, différents bundles (à utiliser dans les frameworks!) Et un aperçu de Nice dans Storyboard, essayez ceci:
// 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
}
}
Utilisez votre xib comme d'habitude, c'est-à-dire connectez les prises au propriétaire du fichier et définissez la classe du propriétaire du fichier sur votre propre classe.
Utilisation: Il suffit de sous-classer votre propre classe View de NibLoadingView.
Aucun code supplémentaire requis plus.
Crédits où le crédit est dû: Cela a été modifié avec des changements mineurs de DenHeadless sur GH. My Gist: https://Gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8
À partir de Swift 2.0, vous pouvez ajouter une extension de protocole. À mon avis, il s'agit d'une meilleure approche car le type de retour est Self
plutôt que UIView
, de sorte que l'appelant n'a pas besoin de transtyper vers la classe d'affichage.
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
}
}
Et voici la réponse de Frederik sur 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
}
}
Mode de chargement universel vue depuis xib:
Exemple:
let myView = Bundle.loadView(fromNib: "MyView", withType: MyView.self)
La mise en oeuvre:
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))
}
}
Réponse de Swift 3: Dans mon cas, je voulais avoir un point de vente dans ma classe personnalisée que je puisse modifier:
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
}
}
Lorsque vous êtes dans le fichier .xib, assurez-vous que le champ Classe personnalisée est MyClassView. Ne vous embêtez pas avec le propriétaire du fichier.
Assurez-vous également que vous connectez la prise de MyClassView à l’étiquette:
Pour l'instancier:
let myClassView = MyClassView.createMyClassView()
myClassView.myLabel.text = "Hello World!"
Swift 4
Ici, dans mon cas, je dois passer des données dans cette vue personnalisée, je crée donc une fonction statique pour instancier la vue.
Créer une extension UIView
extension UIView {
class func initFromNib<T: UIView>() -> T {
return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T
}
}
Créer 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
}
}
Définissez la classe personnalisée sur MyCustomView dans un fichier .xib. Connectez la prise si nécessaire comme d'habitude.
Instancier la vue
let view = MyCustomView.instantiate(message: "Hello World.")
Il existe quelques frameworks, qui implémentent le même code qui est mentionné à plusieurs reprises sur cette page.
Je publie un de ces cadres, LoadableViews .
Et puisque ce cadre est déjà utilisé dans presque toutes les applications de MLSDev, la société sur laquelle je travaille, il sera activement pris en charge dans un avenir prévisible.
Il suffit de poster ici pour quiconque est intéressé.