gpt4 book ai didi

ios - 来自 Xib 的自定义 UIView - 要求,良好实践

转载 作者:行者123 更新时间:2023-11-29 00:01:06 26 4
gpt4 key购买 nike

我正在尝试围绕使用 Xib 文件创建自定义 UIView 的主题进行思考。我已经做过很多次了,但我从来没有想过为什么这个过程如此复杂,哪些部分是必要的,哪些部分是好的等等。而现在,因为 Xibs 是我正在从事的项目的主要组成部分,我开始质疑一切 - 我需要确定发生了什么 😉

假设我们刚刚创建了一个简单的 UIView 子类 - 我们将其命名为 CustomView,该类的基本要求是实现所需的初始化程序,如下所示:

class CustomView: UIView {
// This one is for initializing programmatically
override init(frame: CGRect) {
super.init(frame: frame)
}

// This one is for Storyboards and Xibs
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

当然,我们有关联的 Xib 文件,因此我们实际上要做的第一件事就是转到那里并将文件所有者设置为CustomView

现在,有趣的部分开始了。如果您查看许多在线可用资源( herehere ),每个人都会创建一个从两个初始化程序调用的 commonInit 方法,我知道这是为了在两者之间保持一致性CustomView 的初始化方法,但有点神奇的是为什么在这些方法中我们为 contentView 加载 Nib,并对其施加约束并将它作为 subview 添加到我们的类中?看看代码注释就知道了:

class CustomView: UIView {
@IBOutlet weak var contentView: UIView?
@IBOutlet weak var someSubview: UIView?

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

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

private func commonInit() {
// Why we're loading this `contentView` from Xib?`
self.contentView = loadViewFromNib()
// Why do we have to add it when I's already added in IB?
self.addSubview(contentView)
// Why do we need a constraints for it when IB shows it's filling whole view?
self.contentView.translatesAutoresizingMaskIntoConstraints = false
let trailingAnchor = contentView.trailingAnchor.constraint(equalTo: trailingAnchor)
let leadingAnchor = contentView.leadingAnchor.constraint(equalTo: leadingAnchor)
let topAnchor = contentView.topAnchor.constraint(equalTo: topAnchor)
let bottomAnchor = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
NSLayoutConstraint.activate([trailingAnchor, leadingAnchor, topAnchor, bottomAnchor])
}

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
}
}

下面是令人烦恼的问题:

  • 首先,为什么我们必须向子类添加 contentView
  • contentView 已经是 @IBOutlet 时,为什么我们还要从 Xib 文件加载它?难道不应该免费给我们吗?我想这是为了使用 init(frame:) 从代码中初始化我们的 View ,对吧?
  • 为什么我们需要将此 contentView 添加为 subview 并设置其约束,而 Xib 已经指定了所有内容?

我还看到了上述代码的一个较短版本,没有约束,并且从 Nib 层次结构中完整加载了第一个 UIView:

private func commonInit() {
Bundle.main.loadNibNamed(String(describing: CustomView.self), owner: self, options: nil)

guard let contentView = contentView else { return }
self.addSubview(contentView)
}

它与更详细的方法有何不同?它实际上可以与自动布局和其他一切一起正常工作吗?

最佳答案

有两种方法可以从 Nib 加载自定义 View 。您可以在 IB 中添加一个普通的 UIView 并将此 View 设置为自定义类(类似于 UITableView 子类的设置方式)。注意文件所有者在这种情况下没有被修改。当您从代码中加载 nib 时,您会直接获得一个完全可用的 UIView 子类。您有责任约束它并将其添加到 View 层次结构中。您无法从 IB 本身添加此 View ,因为您无法从 IB 加载它。

第二个是将 XIBs 文件所有者设置为自定义类。这就是 UIViewControllers 在 Storyboards 之前的设置方式。文件所有者是一个代理对象,加载时 IBOutlets 将连接到该代理对象。这支持以编程方式和 IB 本身构建,您只需要在任何 Storyboard 中放置一个自定义 UIView 并将其自定义类设置为您的 UIView 子类,您在自定义子类中添加的代码将加载 XIB 并添加其内容 View 。

直接回答你的问题:

  • 意识到自定义 View 已经从调用代码创建(使用代码中的 MyCustomView() 或 IB 中的 UIView 对象)。因此,为了保留其身份和约束,您能做的最好的事情就是向其添加内容 View 。
  • @IBOutlet 只是一个占位符,表示 socket 将设置为此对象。实际上加载 XIB 必须由您的代码完成(这是由 UIViewController 在加载 Storyboard 时或在 XIB 中使用 init(nibName:bundle:) 构造函数为您完成的)
  • XIB 包含内容 View 的所有内容,而不是自定义 View 。在这种方法中,XIB 中的 View 是一个普通的 UIView,并且必须正确地约束到其父 View (自定义 View )
  • 您提到的较短版本利用 translatesAutoresizingMaskIntoConstraints 创建基于与父 View 相等的框架的约束。

编辑:行 self.contentView = loadViewFromNib() 是无关紧要的。您不需要分配给 contentView(或从 loadViewFromNib 方法返回任何内容。您只需要在 XIB 文件中建立连接,它会自动设置正在加载。owner: self 参数表示您的自定义类将负责处理所有连接

关于ios - 来自 Xib 的自定义 UIView - 要求,良好实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49480436/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com