如何将 xib 文件加载为自定义类?
Posted
技术标签:
【中文标题】如何将 xib 文件加载为自定义类?【英文标题】:How to load a xib file as a custom class? 【发布时间】:2019-06-20 11:10:13 【问题描述】:我正在尝试使用 xib 文件创建可重用组件(在同一个视图中多次),一切都很好,直到我想从 @IBInspectable
属性更新一些控件。我发现@IBOutlet
的那个时候没有设置,所以我搜索了一下,发现了一些东西
http://justabeech.com/2014/07/27/xcode-6-live-rendering-from-nib/
他正在将加载的视图保存到 proxyView 中,以便您可以在 @IBInspectable
中使用它。不幸的是,该代码有点旧,不能按原样工作。但是我的问题是,当我尝试将笔尖作为类加载时,它不起作用。仅当我将其加载为 UIView
时才有效。
这一行失败了
return bundle.loadNibNamed("test", owner: nil, options: nil)?[0] as? ValidationTextField
只有在这种情况下才有效
return bundle.loadNibNamed("test", owner: nil, options: nil)?[0] as? UIView
我认为问题在于,xib 文件的所有者标记为ValidationTextField
,但主视图是UIView
。因此,当您加载笔尖时,它会带来 UIView
,这显然没有自定义属性或插座。
许多关于加载 xib 文件的示例都说类必须在文件所有者中。所以我不知道如何使用它来获取自定义类。
import UIKit
@IBDesignable class ValidationTextField: UIView
@IBOutlet var lblError: UILabel!
@IBOutlet var txtField: XTextField!
@IBOutlet var imgWarning: UIImageView!
private var proxyView: ValidationTextField?
override init(frame: CGRect)
super.init(frame: frame)
required init(coder: NSCoder)
super.init(coder: coder)!
override func awakeFromNib()
super.awakeFromNib()
xibSetup()
override func prepareForInterfaceBuilder()
super.prepareForInterfaceBuilder()
xibSetup()
self.proxyView?.prepareForInterfaceBuilder()
func xibSetup()
guard let view = loadNib() else return
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
// Saving the view in a variable
self.proxyView = view
func loadNib() -> ValidationTextField?
let bundle = Bundle(for: type(of: self))
return bundle.loadNibNamed("test", owner: nil, options: nil)?[0] as? ValidationTextField
@IBInspectable var fontSize: CGFloat = 14.0
didSet
let font = UIFont(name: "System", size: self.fontSize)
self.proxyView!.txtField.font = font
self.proxyView!.lblError.font = font
我什至不知道其余的是否可行。如果链接说的是真的,那么在加载笔尖后获取视图将使我能够访问插座。
在这一行运行该代码失败
guard let view = loadNib() else return
我猜它无法将UIView
转换为类,所以它返回 nil,然后退出。
我的目标是拥有一个可以在单个控制器中多次放置的可重用组件。并且能够在故事板中看到它的设计。
【问题讨论】:
【参考方案1】:将 xibSetup()
移动到您的初始化程序中。 awakeFromNib
被调用太晚,如果视图是以编程方式创建的,它将不会被调用。无需在prepareForInterfaceBuilder
中调用。
简而言之,这可以概括为:
open class NibLoadableView: UIView
public override init(frame: CGRect)
super.init(frame: frame)
loadNibContentView()
commonInit()
public required init?(coder: NSCoder)
super.init(coder: coder)
loadNibContentView()
commonInit()
public func commonInit()
// to be overriden
public extension UIView
// @objc makes it possible to override the property
@objc
var nibBundle: Bundle
return Bundle(for: type(of: self))
// @objc makes it possible to override the property
@objc
var nibName: String
return String(describing: type(of: self))
@discardableResult
func loadNibContentView() -> UIView?
guard
// note that owner = self !!!
let views = nibBundle.loadNibNamed(nibName, owner: self, options: nil),
let contentView = views.first as? UIView
else
return nil
addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = true
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.frame = self.bounds
return contentView
请注意,加载 nib 的视图必须是该视图的所有者。
那么你的班级会变成:
@IBDesignable
class ValidationTextField: NibLoadableView
@IBOutlet var lblError: UILabel!
@IBOutlet var txtField: XTextField!
@IBOutlet var imgWarning: UIImageView!
override func prepareForInterfaceBuilder()
super.prepareForInterfaceBuilder()
commonInit()
override func commonInit()
super.commonInit()
updateFont()
@IBInspectable var fontSize: CGFloat = 14.0
didSet
updateFont()
private func updateFont()
let font = UIFont.systemFont(ofSize: fontSize)
txtField.font = font
lblError.font = font
我想关于代理对象的整个想法来自对 Nib 所有者的滥用。使用代理对象,层次结构必须是这样的:
ValidationTextField
-> ValidationTextField (root view of the nib)
-> txtField, lblError, imgWarning
这没有多大意义。我们真正想要的是:
ValidationTextField (nib owner)
-> UIView (root view of the nib)
-> txtField, lblError, imgWarning
【讨论】:
Nvm,完美运行。谢谢!所以重要的是在 init 函数中加载 nib。我希望他们在 .net 中有类似 UserControls 的东西,这样更易于使用和理解。 @dpaladin 重要的是要了解 nib 是如何加载的,它的所有者是什么,并停止使用那些疯狂的代理对象 :)以上是关于如何将 xib 文件加载为自定义类?的主要内容,如果未能解决你的问题,请参考以下文章
无法为自定义 UITableView 单元设置约束,在 xib 中创建,因为所有数据在大小类更改时消失
如何从 XIB 文件加载自定义创建的视图并添加到 StackView