在Swift中从nib加载UIView

时间:2014-07-21 04:57:13

标签: swift uiview xib

以下是我用于为自定义UIView加载笔尖的Objective-C代码:

-(id)init{

    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"myXib" owner:self options:nil];
    return [subviewArray objectAtIndex:0];

}

Swift中的等效代码是什么?

28 个答案:

答案 0 :(得分:241)

我的贡献:

extension UIView {
    class func fromNib<T: UIView>() -> T {
        return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
    }
}

然后这样称呼:

let myCustomView: CustomView = UIView.fromNib()

..甚至:

let myCustomView: CustomView = .fromNib()

答案 1 :(得分:151)

原始解决方案

  1. 我创建了一个名为SomeView的XIB和一个类(使用相同的名称) 方便和可读性)。我基于UIView。
  2. 在XIB中,我更改了&#34;文件的所有者&#34; class to SomeView(在身份检查器中)。
  3. 我在SomeView.swift中创建了一个UIView插座,将其链接到XIB文件中的顶级视图(为了方便起见,将其命名为&#34; view&#34;)。然后,我根据需要将其他插座添加到XIB文件中的其他控件。
  4. 在SomeView.swift中,我将XIB加载到&#34; init中,代码为&#34;初始化。没有必要为&#34; self&#34;分配任何内容。加载XIB后,所有插座都会连接,包括顶层视图。唯一缺少的是将顶视图添加到视图层次结构中:
  5. class SomeView: UIView {
       required init(coder aDecoder: NSCoder) {
          super.init(coder: aDecoder)
          NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
          self.addSubview(self.view);    // adding the top level view to the view hierarchy
       }
       ...
    }
    

    请注意,这样我获得了一个从nib加载自身的类。然后,只要UIView可以在项目中使用(在界面构建器中或以编程方式),我就可以将SomeView用作类。

    更新 - 使用Swift 3语法

    在以下扩展名中加载xib是作为实例方法编写的,然后可以像上面的初始化程序一样使用它:

    extension UIView {
    
        @discardableResult   // 1
        func fromNib<T : UIView>() -> T? {   // 2
            guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {    // 3
                // xib not loaded, or its top view is of the wrong type
                return nil
            }
            self.addSubview(contentView)     // 4
            contentView.translatesAutoresizingMaskIntoConstraints = false   // 5 
            contentView.layoutAttachAll(to: self)   // 6 
            return contentView   // 7
        }
    }
    
    1. 使用可废弃的返回值,因为当所有插座已经连接时,返回的视图对调用者来说几乎没有兴趣。
    2. 这是一个返回UIView类型的可选对象的通用方法。如果无法加载视图,则返回nil。
    3. 尝试加载与当前类实例同名的XIB文件。如果失败,则返回nil。
    4. 将顶级视图添加到视图层次结构中。
    5. 此行假设我们使用约束来布局视图。
    6. 此方法增加了top,bottom,leading&amp;尾随约束 - 将视图附加到&#34; self&#34;各方面(详见https://stackoverflow.com/a/46279424/2274829
    7. 返回顶级视图
    8. 调用者方法可能如下所示:

      final class SomeView: UIView {   // 1.
         required init?(coder aDecoder: NSCoder) {   // 2 - storyboard initializer
            super.init(coder: aDecoder)
            fromNib()   // 5.
         }
         init() {   // 3 - programmatic initializer
            super.init(frame: CGRect.zero)  // 4.
            fromNib()  // 6.
         }
         // other methods ...
      }
      
      1. SomeClass是一个UIView子类,它从SomeClass.xib文件加载其内容。 &#34;决赛&#34;关键字是可选的。
      2. 用于在故事板中使用视图的初始化程序(请记住使用SomeClass作为故事板视图的自定义类)。
      3. 用于以编程方式创建视图的初始化程序(即:&#34;让myView = SomeView()&#34;)。
      4. 使用全零帧,因为此视图使用自动布局布局。 注意&#34; init(frame:CGRect){..}&#34;方法不是独立创建的,因为自动布局仅在我们的项目中使用。
      5. &安培; 6.使用扩展名加载xib文件。
      6. 信用:在此解决方案中使用通用扩展程序的灵感来自Robert的答案如下。

        修改 改变&#34;观看&#34;到&#34; contentView&#34;避免混淆。还将数组下标更改为&#34; .first&#34;。

答案 2 :(得分:76)

这是一个使用泛型从笔尖加载UIView的扩展程序

public extension UIView {
    public class func fromNib(nibNameOrNil: String? = nil) -> Self {
        return fromNib(nibNameOrNil, type: self)
    }

    public class func fromNib<T : UIView>(nibNameOrNil: String? = nil, type: T.Type) -> T {
        let v: T? = fromNib(nibNameOrNil, type: T.self)
        return v!
    }

    public class func fromNib<T : UIView>(nibNameOrNil: String? = nil, type: T.Type) -> T? {
        var view: T?
        let name: String
        if let nibName = nibNameOrNil {
            name = nibName
        } else {
            // Most nibs are demangled by practice, if not, just declare string explicitly
            name = nibName
        }
        let nibViews = NSBundle.mainBundle().loadNibNamed(name, owner: nil, options: nil)
        for v in nibViews {
            if let tog = v as? T {
                view = tog
            }
        }
        return view
    }

    public class var nibName: String {
        let name = "\(self)".componentsSeparatedByString(".").first ?? ""
        return name
    }
    public class var nib: UINib? {
        if let _ = NSBundle.mainBundle().pathForResource(nibName, ofType: "nib") {
            return UINib(nibName: nibName, bundle: nil)
        } else {
            return nil
        }
    }
}

我更喜欢这个,因为它不需要在笔尖中进行任何额外的设置。它基于通用命名约定,因此如果您的类为CustomView,并且它与名为CustomView的nib匹配,则可以执行此操作:

let myCustomView = CustomView.fromNib()
// or if you're unsure whether or not the nib exists
let myCustomView: CustomView? = CustomView.fromNib()

如果您因任何原因需要具体说明笔尖名称,请传递字符串arg:

let myCustomView = MyCustomView.fromNib("non-conventional-name")

已知问题

将此与私有视图类一起使用似乎会导致问题。这似乎是一个系统问题。

答案 3 :(得分:16)

尝试以下代码。

var uiview :UIView?

self.uiview = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)[0] as? UIView

修改

import UIKit

class TestObject: NSObject {

     var uiview:UIView?

    init()  {
        super.init()
       self.uiview = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)[0] as? UIView
    }


}

答案 4 :(得分:10)

我通过以下代码用Swift实现了这个目标:

class Dialog: UIView {
    @IBOutlet var view:UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.frame = UIScreen.mainScreen().bounds
        NSBundle.mainBundle().loadNibNamed("Dialog", owner: self, options: nil)
        self.view.frame = UIScreen.mainScreen().bounds
        self.addSubview(self.view)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

不要忘记将您的XIB 视图插座连接到swift中定义的 view 插座。您还可以将First Responder设置为您的自定义类名称,以开始连接任何其他插座。

希望这有帮助!

答案 5 :(得分:9)

在Xcode 7 beta 4,Swift 2.0和iOS9 SDK中测试过。 以下代码将xib分配给uiview。 您可以在故事板中使用此自定义xib视图,也可以访问IBOutlet对象。

import UIKit

@IBDesignable class SimpleCustomView:UIView
{
    var view:UIView!;

    @IBOutlet weak var lblTitle: UILabel!

   @IBInspectable var lblTitleText : String?
        {
        get{
            return lblTitle.text;
        }
        set(lblTitleText)
        {
            lblTitle.text = lblTitleText!;
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        loadViewFromNib ()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadViewFromNib ()
    }
    func loadViewFromNib() {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "SimpleCustomView", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        self.addSubview(view);



    }


}

以编程方式访问customview

self.customView =  SimpleCustomView(frame: CGRectMake(100, 100, 200, 200))
        self.view.addSubview(self.customView!);

源代码 - https://github.com/karthikprabhuA/CustomXIBSwift

答案 6 :(得分:7)

如果您的项目中有很多自定义视图,则可以创建类似UIViewFromNib

的类

Swift 2.3

class UIViewFromNib: UIView {

    var contentView: UIView!

    var nibName: String {
        return String(self.dynamicType)
    }

    //MARK:
    override init(frame: CGRect) {
        super.init(frame: frame)

        loadViewFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        loadViewFromNib()
    }

    //MARK:
    private func loadViewFromNib() {
        contentView = NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0] as! UIView
        contentView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        contentView.frame = bounds
        addSubview(contentView)
    }
}

Swift 3

class UIViewFromNib: UIView {

    var contentView: UIView!

    var nibName: String {
        return String(describing: type(of: self))
    }

    //MARK:
    override init(frame: CGRect) {
        super.init(frame: frame)

        loadViewFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        loadViewFromNib()
    }

    //MARK:
    func loadViewFromNib() {
        contentView = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?[0] as! UIView
        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        contentView.frame = bounds
        addSubview(contentView)
    }
}

并且在每个类中只继承自UIViewFromNib,如果nibName文件具有不同的名称,您也可以覆盖.xib属性:

class MyCustomClass: UIViewFromNib {

}

答案 7 :(得分:7)

Swift 4协议扩展

public protocol NibInstantiatable {

    static func nibName() -> String

}

extension NibInstantiatable {

    static func nibName() -> String {
        return String(describing: self)
    }

}

extension NibInstantiatable where Self: UIView {

    static func fromNib() -> Self {

        let bundle = Bundle(for: self)
        let nib = bundle.loadNibNamed(nibName(), owner: self, options: nil)

        return nib!.first as! Self

    }

}

采用

class MyView: UIView, NibInstantiatable {

}

此实现假定Nib与UIView类具有相同的名称。例如MyView.xib。您可以通过在MyView中实现nibName()返回与默认协议扩展实现不同的名称来修改此行为。

在xib中,文件所有者是MyView,根视图类是MyView。

用法

let view = MyView.fromNib()

答案 8 :(得分:7)

基于上述解决方案。

这将适用于所有项目包,并且在调用fromNib()时不需要泛型。

Swift 2

$re = '@\b(([\w-]+://?|www[.])[^\s()<>]+(?:\(\w+\)|([^[:punct:]\s]|/)))@i';
$str = "www.domain.com\nhttp://www.domain.com\nhttp://domain.com";
$subst = '<a href="$0" target="_blank">$0</a> ';
$result = preg_replace($re, $subst, $str);
echo $result;

Swift 3

<a href="www.domain.com" target="_blank">www.domain.com</a> 
<a href="http://www.domain.com" target="_blank">http://www.domain.com</a> 
<a href="http://domain.com" target="_blank">http://domain.com</a> 

可以像这样使用:

extension UIView {

    public class func fromNib() -> Self {
        return fromNib(nil)
    }

    public class func fromNib(nibName: String?) -> Self {

        func fromNibHelper<T where T : UIView>(nibName: String?) -> T {
            let bundle = NSBundle(forClass: T.self)
            let name = nibName ?? String(T.self)
            return bundle.loadNibNamed(name, owner: nil, options: nil)?.first as? T ?? T()
        }
        return fromNibHelper(nibName)
    }
}

或者像这样:

extension UIView {

    public class func fromNib() -> Self {
        return fromNib(nibName: nil)
    }

    public class func fromNib(nibName: String?) -> Self {
        func fromNibHelper<T>(nibName: String?) -> T where T : UIView {
            let bundle = Bundle(for: T.self)
            let name = nibName ?? String(describing: T.self)
            return bundle.loadNibNamed(name, owner: nil, options: nil)?.first as? T ?? T()
        }
        return fromNibHelper(nibName: nibName)
    }
}

答案 9 :(得分:5)

使用Swift执行此操作的一个好方法是使用枚举。

let view = Views.view1.getView()

然后在您的代码中,您只需使用:

<?php
//reciever
$to      = 'julius.kroon@gmail.com';
//subject
$subject = 'new costumer';
//form information
$title = "";
$name = "";
$companyname = "";
$mail = "";
$extrapages = "";
$sow = "";
if(isset($_POST['title'])){ $title = $_POST['title']; } //title
if(isset($_POST['name'])){ $name = $_POST['name']; } //name
if(isset($_POST['companyname'])){ $companyname = $_POST['companyname']; }          //company name
if(isset($_POST['mail'])){ $mail = $_POST['mail']; } //email
if(isset($_POST['extrapages'])){ $extrapages = $_POST['extrapages']; } //extra         pages
if(isset($_POST['sow'])){ $sow = $_POST['sow']; } //site on web
$message ="
title = $title
name = $name
companyname = $companyname
mail = $mail
extra pages = $extrapages
site on web = $sow
";
//header
$headers = 'From: webmaster@example.com' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();
//mail code
mail($to, $subject, $message, $headers);
?>

答案 10 :(得分:3)

我更喜欢这个解决方案(基于@ GK100的答案):

  1. 我创建了一个名为SomeView的XIB和一个类(为了方便和可读性,使用了相同的名称)。我基于UIView。
  2. 在XIB中,我更改了&#34;文件的所有者&#34; class to SomeView(在身份检查器中)。
  3. 我在SomeView.swift中创建了一个UIView插座,将其链接到XIB文件中的顶级视图(为了方便起见,将其命名为&#34; view&#34;)。然后,我根据需要将其他插座添加到XIB文件中的其他控件。
  4. 在SomeView.swift中,我将XIB加载到initinit:frame: CGRect初始值设定项中。没有必要为&#34; self&#34;分配任何内容。加载XIB后,所有插座都会连接,包括顶层视图。唯一缺少的是将顶视图添加到视图层次结构中:

    class SomeView: UIView {
      override init(frame: CGRect) {
        super.init(frame: frame)
        NSBundle.mainBundle().loadNibNamed("SomeObject", owner: self, options: nil)
        self.addSubview(self.view);    // adding the top level view to the view hierarchy
      }
    
      required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        NSBundle.mainBundle().loadNibNamed("SomeObject", owner: self, options: nil)
        self.addSubview(self.view);    // adding the top level view to the view hierarchy
      }
    
    
      ...
    }
    

答案 11 :(得分:3)

斯威夫特3 版本的洛根回答

extension UIView {
    public class func fromNib(nibName: String? = nil) -> Self {
        return fromNib(nibName: nibName, type: self)
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T {
        return fromNib(nibName: nibName, type: T.self)!
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T? {
        var view: T?
        let name: String

        if let nibName = nibName {
            name = nibName
        } else {
            name = self.nibName
        }

        if let nibViews = Bundle.main.loadNibNamed(name, owner: nil, options: nil) {
            for nibView in nibViews {
                if let tog = nibView as? T {
                    view = tog
                }
            }
        }

        return view
    }

    public class var nibName: String {
        return "\(self)".components(separatedBy: ".").first ?? ""
    }

    public class var nib: UINib? {
        if let _ = Bundle.main.path(forResource: nibName, ofType: "nib") {
            return UINib(nibName: nibName, bundle: nil)
        } else {
            return nil
        }
    }
}

答案 12 :(得分:3)

let subviewArray = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)
return subviewArray[0]

答案 13 :(得分:2)

我就是这样做的:

if let myView = UINib.init(nibName: "MyView", bundle: nil).instantiate(withOwner: self)[0] as? MyView {
// Do something with myView
}

此示例使用主包中nib“MyView.xib”中的第一个视图。但您可以改变索引,笔尖名称或包(默认为main)。

我过去常常将视图唤醒到视图init方法或制作通用方法,就像上面的解决方案一样(顺便说一句,它是聪明的),但我不再这样做了。

这样我可以使用不同的布局或特征,同时保持相同的视图逻辑和代码。

我发现更容易让工厂对象(通常是将使用该视图的viewController)根据需要创建它。有时候你需要一个拥有者(通常当创建的视图有一个连接到创建者的插座时),有时候不是..

这可能就是为什么Apple在其UIView类中没有包含initFromNib方法的原因......

举一个基层的例子,你不知道你是如何出生的。你刚出生。观点也是如此;)

答案 14 :(得分:2)

这是一种使用协议和协议扩展(Swift 4.2)以编程方式加载视图的简洁声明方式:

protocol XibLoadable {
    associatedtype CustomViewType
    static func loadFromXib() -> CustomViewType
}

extension XibLoadable where Self: UIView {
    static func loadFromXib() -> Self {
        let nib = UINib(nibName: "\(self)", bundle: Bundle(for: self))
        guard let customView = nib.instantiate(withOwner: self, options: nil).first as? Self else {
            // your app should crash if the xib doesn't exist
            preconditionFailure("Couldn't load xib for view: \(self)")
        }
        return customView
    }
}

您可以像这样使用它:

// don't forget you need a xib file too
final class MyView: UIView, XibLoadable { ... }

// and when you want to use it
let viewInstance = MyView.loadFromXib()

一些其他注意事项

  1. 请确保您的自定义视图的xib文件具有该视图的Custom Class集(以及从那里设置的出口/操作),而不是文件所有者的。
  2. 您可以在自定义视图外部或内部使用此协议/扩展。如果在初始化视图时还有其他设置工作,则可能需要在内部使用它。
  3. 您的自定义视图类和xib文件必须具有相同的名称。

答案 15 :(得分:2)

快捷键4

别忘了写“ .first as?CustomView”。

if let customView = Bundle.main.loadNibNamed("myXib", owner: self, options: nil)?.first as? CustomView {    
    self.view.addSubview(customView)
    }

如果您想在任何地方使用

最佳解决方案是 Robert Gummesson 的答案。

extension UIView {
    class func fromNib<T: UIView>() -> T {
        return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
    }
}

然后这样称呼它:

let myCustomView: CustomView = UIView.fromNib()

答案 16 :(得分:2)

您只需在UIView课程中调用init方法。

这样做:

class className: UIView {

    @IBOutlet var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }

    func setup() {
        UINib(nibName: "nib", bundle: nil).instantiateWithOwner(self, options: nil)
        addSubview(view)
        view.frame = self.bounds
    }
}

现在,如果要在视图控制器中将此视图添加为子视图,请在视图controller.swift文件中执行此操作:

self.view.addSubview(className())

答案 17 :(得分:1)

您可以通过storyboard执行此操作,只需为视图添加适当的约束即可。您可以通过从您自己的BaseView

中继承任何视图来轻松完成此操作

<强>目标C

BaseView.h


/*!
 @class BaseView
 @discussion Base View for getting view from xibFile
 @availability ios7 and later
 */
@interface BaseView : UIView

@end


BaseView.m


#import "BaseView.h"

@implementation BaseView

#pragma mark - Public

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self prepareView];
    }
    return self;
}

#pragma mark - LifeCycle

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self prepareView];
    }
    return self;
}

#pragma mark - Private

- (void)prepareView
{
    NSArray *nibsArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
    UIView *view = [nibsArray firstObject];

    view.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:view];
    [self addConstraintsForView:view];
}

#pragma mark - Add constraints

- (void)addConstraintsForView:(UIView *)view
{
    [self addConstraints:@[[NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeBottom
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeBottom
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeTop
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeTop
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeLeft
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeLeft
                                                       multiplier:1.0
                                                         constant:0],
                           [NSLayoutConstraint constraintWithItem:view
                                                        attribute:NSLayoutAttributeRight
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:self attribute:NSLayoutAttributeRight
                                                       multiplier:1.0
                                                         constant:0]
                           ]];
}

@end

Swift 4

import UIKit

class BaseView : UIView {

    // MARK: - LifeCycle

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        prepareView()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        prepareView()
    }

    internal class func xibName() -> String {
        return String(describing: self)
    }

    // MARK: - Private
    fileprivate func prepareView() {
        let nameForXib = BaseView.xibName()
        let nibs = Bundle.main.loadNibNamed(nameForXib, owner: self, options: nil)
        if let view = nibs?.first as? UIView {
            view.backgroundColor = UIColor.clear
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubviewWithConstraints(view, offset: false)
        }
    }
}

UIView+Subview


public extension UIView {
    // MARK: - UIView+Extensions

    public func addSubviewWithConstraints(_ subview:UIView, offset:Bool = true) {
        subview.translatesAutoresizingMaskIntoConstraints = false
        let views = [
            "subview" : subview
        ]
        addSubview(subview)

        var constraints = NSLayoutConstraint.constraints(withVisualFormat: offset ? "H:|-[subview]-|" : "H:|[subview]|", options: [.alignAllLeading, .alignAllTrailing], metrics: nil, views: views)
        constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: offset ? "V:|-[subview]-|" : "V:|[subview]|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views))
        NSLayoutConstraint.activate(constraints)
    }
}

我提供2种变体如何添加约束 - 常见的和可视化格式语言 - 选择你想要的任何:)

此外,默认情况下假设xib名称与实现类名称相同。如果不是 - 只需更改xibName参数。

如果您从BaseView继承视图 - 您可以轻松地放置任何视图并在IB中指定类。

答案 18 :(得分:1)

class func loadFromNib<T: UIView>() -> T {
    let nibName = String(describing: self)
    return Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)![0] as! T
}

答案 19 :(得分:1)

与上面的一些答案类似,但更加一致的Swift3 UIView扩展名:

extension UIView {
    class func fromNib<A: UIView> (nibName name: String, bundle: Bundle? = nil) -> A? {
        let bundle = bundle ?? Bundle.main
        let nibViews = bundle.loadNibNamed(name, owner: self, options: nil)
        return nibViews?.first as? A
    }

    class func fromNib<T: UIView>() -> T? {
        return fromNib(nibName: String(describing: T.self), bundle: nil)
    }
}

这样可以方便地从自己命名的nib加载类,也可以从其他nibs / bundle加载。

答案 20 :(得分:1)

    let nibs = Bundle.main.loadNibNamed("YourView", owner: nil, options: nil)
    let shareView = nibs![0] as! ShareView
    self.view.addSubview(shareView)

答案 21 :(得分:1)

Swift 5-清洁易用的扩展程序

[从生产项目复制粘贴]

//
//  Refactored by Essam Mohamed Fahmi.
//

import UIKit

extension UIView
{
   static var nib: UINib
   {
      return UINib(nibName: "\(self)", bundle: nil)
   }

   static func instantiateFromNib() -> Self?
   {
      return nib.instantiate() as? Self
   }
}

extension UINib
{
   func instantiate() -> Any?
   {
      return instantiate(withOwner: nil, options: nil).first
   }
}

用法

let myCustomView: CustomView = .instantiateFromNib()

答案 22 :(得分:0)

如果你希望Swift UIView子类完全是自包含的,并且能够使用init或init(frame :)实例化而不暴露使用Nib的实现细节,那么你可以使用协议扩展来实现这个。此解决方案避免了许多其他解决方案所建议的嵌套UIView层次结构。

describe('method add', function() {
    it('should add', function() {
        spyOn(SomeService, 'add').and.callFake(function(id, successCallback, errorCallback) {
            successCallback();
        });
        spyOn(scope, 'showSuccessMessage');
        scope.add();
        $timeout.flush();
        expect(SomeService.add).toHaveBeenCalled();
        expect(scope.showSuccessMessage).toHaveBeenCalled();
    });
});

答案 23 :(得分:0)

最方便的实现。在这里,您需要两种方法,以便直接返回到您的类的对象,而不是UIView。

  1. viewId标记为,允许覆盖
  2. 您的.xib可以包含多个顶级视图,这种情况也是如此 处理得当。
  3. extension UIView {
    
    class var viewId: String {
        return String(describing: self)
    }
    
    static func instance(from bundle: Bundle? = nil, nibName: String? = nil,
                        owner: Any? = nil, options: [AnyHashable : Any]? = nil) -> Self? {
    
        return instancePrivate(from: bundle ?? Bundle.main,
                               nibName: nibName ?? viewId,
                               owner: owner,
                               options: options)
    }
    
    private static func instancePrivate<T: UIView>(from bundle: Bundle, nibName: String,
                                                  owner: Any?, options: [AnyHashable : Any]?) -> T? {
    
        guard
            let views = bundle.loadNibNamed(nibName, owner: owner, options: options),
            let view = views.first(where: { $0 is T }) as? T else { return nil }
    
        return view
    }
    }
    

    示例:

    guard let customView = CustomView.instance() else { return }
    
    //Here customView has CustomView class type, not UIView.
    print(customView is CustomView) // true
    

答案 24 :(得分:0)

基于Logan答案的更强大的版本

@PropertySource("classpath:{whatever_you_want_path}")

你可以使用

extension UIView {
    public class func fromNib(nibName: String? = nil) -> Self {
        return fromNib(nibName: nibName, type: self)
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T {
        return fromNib(nibName: nibName, type: T.self)!
    }

    public class func fromNib<T: UIView>(nibName: String? = nil, type: T.Type) -> T? {
        var view: T?
        let name: String

        if let nibName = nibName {
            name = nibName
        } else {
            name = self.nibName
        }

        if let nibViews = nibBundle.loadNibNamed(name, owner: nil, options: nil) {
            if nibViews.indices.contains(nibIndex), let tog = nibViews[nibIndex] as? T {
                view = tog
            }
        }

        return view
    }

    public class var nibName: String {
        return "\(self)".components(separatedBy: ".").first ?? ""
    }

    public class var nibIndex: Int {
        return 0
    }

    public class var nibBundle: Bundle {
        return Bundle.main
    }
}

答案 25 :(得分:0)

  let bundle = Bundle(for: type(of: self))
   let views = bundle.loadNibNamed("template", owner: self, options: nil)
    self.view.addSubview(views?[0] as! UIView)

答案 26 :(得分:0)

我更喜欢下面的扩展名

extension UIView {
    class var instanceFromNib: Self {
        return Bundle(for: Self.self)
            .loadNibNamed(String(describing: Self.self), owner: nil, options: nil)?.first as! Self
    }
}

此扩展名与顶部回答的扩展名之间的区别是您不需要将其存储为常量或变量。

class TitleView: UIView { }

extension UIView {
    class var instanceFromNib: Self {
        return Bundle(for: Self.self)
            .loadNibNamed(String(describing: Self.self), owner: nil, options: nil)?.first as! Self
    }
}

self.navigationItem.titleView = TitleView.instanceFromNib

答案 27 :(得分:0)

// 使用这个类作为超级视图

import UIKit

class ViewWithXib: UIView {

func initUI() {}

private func xibSetup() {
    let view = loadViewFromNib()
    view.frame = bounds
    view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
    addSubview(view)
    initUI()
}

private func loadViewFromNib() -> UIView {
    let thisName = String(describing: type(of: self))
    let view = Bundle(for: self.classForCoder).loadNibNamed(thisName, owner: self, options: nil)?.first as! UIView
    return view
}


override init(frame: CGRect) {
    super.init(frame: frame)
    xibSetup()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    xibSetup()
}

}

// 用法:

class HeaderView: ViewWithXib {
}


let header = HeaderView() // No need to load the view from nib, It will work