小编典典

在 Swift 中从 nib 加载 UIView

all

这是我用来为我的自定义加载笔尖的 Objective-C 代码UIView

-(id)init{

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

}

Swift 中的等效代码是什么?


阅读 82

收藏
2022-08-19

共1个答案

小编典典

原始解决方案

  1. 我创建了一个 XIB 和一个名为 SomeView 的类(为了方便和可读性,使用相同的名称)。我都基于 UIView。
  2. 在 XIB 中,我将“文件所有者”类更改为 SomeView(在身份检查器中)。
  3. 我在 SomeView.swift 中创建了一个 UIView 插座,将其链接到 XIB 文件中的顶级视图(为方便起见,将其命名为“视图”)。然后,我根据需要将其他插座添加到 XIB 文件中的其他控件。
  4. 在 SomeView.swift 中,我在“init with code”初始化程序中加载了 XIB。没有必要为“自我”分配任何东西。加载 XIB 后,所有插座都已连接,包括顶层视图。唯一缺少的是将顶视图添加到视图层次结构中:

.

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. 此方法添加顶部、底部、前导和尾随约束 - 将视图附加到所有侧面的“自我”(有关详细信息,请参阅:https ://stackoverflow.com/a/46279424/2274829 )
  7. 返回顶层视图

调用者方法可能如下所示:

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 文件中加载其内容。“final”关键字是可选的。
  2. 用于在情节提要中使用视图时的初始化程序(请记住使用 SomeClass 作为情节提要视图的自定义类)。
  3. 以编程方式创建视图时的初始化程序(即:“let myView = SomeView()”)。
  4. 使用全零框架,因为此视图是使用自动布局布局的。请注意,“init(frame: CGRect) {..}”方法不是独立创建的,因为自动布局仅在我们的项目中使用。
  5. & 6. 使用扩展名加载 xib 文件。

学分:在此解决方案中使用通用扩展的灵感来自 Robert 在下面的回答。

编辑 将“view”更改为“contentView”以避免混淆。还将数组下标更改为“.first”。

2022-08-19