首页 文章

如何在Swift中使用XIB文件初始化/实例化自定义UIView类

提问于
浏览
103

我有一个名为 MyClass 的类,它是 UIView 的子类,我想用 XIB 文件进行初始化 . 我不知道如何使用名为 View.xib 的xib文件初始化此类

class MyClass: UIView {

    // what should I do here? 
    //init(coder aDecoder: NSCoder) {} ?? 
}

9 回答

  • 20

    从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
      }
    
    }
    
  • 24

    我测试了这段代码,效果很好

    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)
    

    OR

    var view = MyClass.instanceFromNib
        self.view.addSubview(view())
    

    UDATE Swift >=3.x

    class func instanceFromNib() -> UIView {
        return UINib(nibName: "nib file name", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
    }
    
  • 71

    Sam的解决方案已经很好了,尽管它没有考虑不同的捆绑(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并将File Owner类设置为你自己的类 .

    Usage: Just subclass your own View class from NibLoadingView.

    不再需要其他代码 .

    信用额到期的信用额度:来自DenHeadless对GH的微小变化 . 我的要点:https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8

  • 6

    这就是Frederik在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
        }
    }
    
  • 214

    从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))
        }
    }
    
  • 0

    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 . 不要打扰文件所有者 .

    Make sure Custom Class is MyClassView

    此外,请确保将MyClassView中的插座连接到标签:
    Outlet for myLabel

    要实例化它:

    let myClassView = MyClassView.createMyClassView()
    myClassView.myLabel.text = "Hello World!"
    
  • 34

    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
        }
    }
    
    • 在.xib文件中将自定义类设置为MyCustomView . 如有必要,照常连接插座 .
      enter image description here

    • 实例化视图

    let view = MyCustomView.instantiate(message: "Hello World.")
    
  • 1

    有一些框架实现了在此页面上多次提到的相同代码 .

    我正在发布其中一个这样的框架,LoadableViews .

    由于这个框架已经在MLSDev的几乎所有应用程序中使用,我正在研究的公司,它将在可预见的未来得到积极支持 .

    只是发布在这里感兴趣的人 .

  • 70
    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)
    
            })
        })
    
    
    }
    

相关问题