MyClass
というサブクラスであるというクラスがありUIView
、XIB
ファイルで初期化したいと思います。呼び出されたxibファイルでこのクラスを初期化する方法がわかりませんView.xib
class MyClass: UIView {
// what should I do here?
//init(coder aDecoder: NSCoder) {} ??
}
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())
UPDATE 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())
。答えを改善するためのほんの小さな提案:)
Samのソリューションはすでに優れていますが、さまざまなバンドルが考慮されておらず(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を使用します。つまり、アウトレットをファイル所有者に接続し、ファイル所有者クラスを独自のクラスに設定します。
使用法:NibLoadingViewから独自のViewクラスをサブクラス化し、クラス名をXibファイルのFile's Ownerに設定します
追加のコードは必要ありません。
クレジット期限のあるクレジット:GHのDenHeadlessからの小さな変更でこれを分岐しました。私の要点:https : //gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8
nibSetup
からinit?(coder:)
埋め込む場合、無限再帰が発生しますNibLoadingView
XIBに。
.clearColor()
、ストーリーボードからロードした後に、nibSetup()が背景色をオーバーライドするためと考えられます。しかし、インスタンス化された後にコードで実行すれば機能するはずです。とにかく、前述したように、さらに洗練されたアプローチはプロトコルベースのアプローチです。ですから、ここにリンクがあります:github.com/AliSoftware/Reusable。私はUITableViewCells(本当に便利なプロジェクトを発見する前に実装しました)に関して同様のアプローチを使用しています。ああ!
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でのFrederikの答えです
/*
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 Answer:私の場合、カスタムクラスに変更可能なアウトレットを用意したいと思いました。
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にある場合は、[カスタムクラス]フィールドがMyClassViewであることを確認します。ファイルの所有者に迷惑をかけないでください。
また、MyClassViewのコンセントをラベルに接続していることを確認してください。
それをインスタンス化するには:
let myClassView = MyClassView.createMyClassView()
myClassView.myLabel.text = "Hello World!"
スウィフト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
}
}
.xibファイルでカスタムクラスをMyCustomViewに設定します。必要に応じて、通常どおりコンセントを接続します。
ビューをインスタンス化
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)
})
})
}