Как инициализировать/создать экземпляр класса 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

Здесь, в моем случае, я должен передать данные в это пользовательское представление, поэтому я создаю статическую функцию для создания экземпляра представления.

  1. Создать расширение UIView

    extension UIView {
        class func initFromNib<T: UIView>() -> T {
            return Bundle.main.loadNibNamed(String(describing: self), owner: nil, options: nil)?[0] as! T
        }
    }
    
  2. Создать 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
        }
    }
    
  3. Установите пользовательский класс для MyCustomView в файле .xib. Подключите розетку, если необходимо, как обычно. enter image description here

  4. Инстанцирующий вид

    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)

        })
    })


}