在视图控制器中访问 UIView 子类
Posted
技术标签:
【中文标题】在视图控制器中访问 UIView 子类【英文标题】:accessing UIView subclass in view controller 【发布时间】:2020-02-07 13:24:05 【问题描述】:假设我有SomeViewController: UIViewController
,我有一个自定义视图CustomView: UIView
,定义为XIB,我想显示它。这个自定义视图将在其他视图控制器中重复使用,甚至在同一个视图控制器中重复使用多次。
class CustomView: UIView
@IBOutlet public var label: UILabel!
我一直添加这个视图的方式是:
class UIExamples: UIViewController
@IBOutlet private var myView: UIView!
override func viewDidLoad()
super.viewDidLoad()
// Assume makeViewFromNib returns the view [0] in the Nib.
let customView = makeViewFromNib(nib: "\(CustomView.self)", owner: self) as! CustomView
customView.frame = myView.bounds
myView.addSubview(customView)
假设稍后我想通过公共属性label
修改有关CustomView
的内容。
我可以在viewDidLoad
中进行操作,只是因为我可以访问customView
,但是如果我想在其他一些函数中更改它怎么办?我所看到的是一个人必须做的事情
let customView = myView.subviews[0] as! CustomView
customView.label.text = "some text"
这看起来不对。
所以,我认为正确的方法应该是:
class UIExamples: UIViewController
@IBOutlet public var customView: CustomView! // Now this is always a CustomView type
override func viewDidLoad()
super.viewDidLoad()
// Assume makeViewFromNib returns the view [0] in the Nib.
customView = makeViewFromNib(nib: "\(CustomView.self)", owner: self) as! CustomView
customView.label.text = "some text" // DOES NOT WORK!
最后一行 customView.label.text 不起作用。事实上,标签甚至在屏幕上都看不到。我究竟做错了什么?
【问题讨论】:
你不需要显式调用makeViewFromNib(nib: "\(CustomView.self)", owner: self)
,因为如果你在这种情况下使用IBOutlet
,你已经从Storyboard加载了customView
。下一点你应该澄清——你使用的是 Storyboard 还是 Xib。
您想在不同的视图控制器中重用视图还是专门针对那个控制器?
在第一句中添加了说明。
也许看看这里:medium.com/@letatas/…你可能会找到问题的答案
【参考方案1】:
好的,没有阅读(或者可能在编辑之前阅读)您使用 xib。如果 ViewController 是从带有标签的 xib 创建的,这将是正确的方法:
在此处设置 xib 中的 myView 类:
然后连接IBOutlet(这里从xib中删除当前一个:
然后从代码)。
现在myView.label.text = "some text"
应该可以正常工作了。
祝你好运!
如果您从代码创建视图,请按以下方式进行:
class UIExamples: UIViewController
@IBOutlet private var myView: CustomView!
override func viewDidLoad()
super.viewDidLoad()
// Assume makeViewFromNib returns the view [0] in the Nib.
myView = makeViewFromNib(nib: "\(CustomView.self)", owner: self) as! CustomView
myView.frame = view.bounds
view.addSubview(myView)
因为您已经在视图控制器中存储了这个视图的属性,所以没有必要在子视图中挖掘,它会像那样工作
myView.label.text = "some text"
以及原因
customView = makeViewFromNib(nib: "\(CustomView.self)", owner: self) as! CustomView
customView.label.text = "some text"
不起作用是因为它是全新的视图,没有添加到您的视图控制器子视图中(顺便说一句,框架也没有设置)。而且因为您更改了 customView 属性的值,它现在不指向旧视图实例,它存在于子视图中(您仍然可以看到“旧的”但不能更改它)。
但我真的建议使用创建一次的指针,作为正确的类以避免强制转换。 (或者直接在xib/storyboard中创建view,否则@IBOutlet
就不需要了)
【讨论】:
我注意到 myView.subviews 的类型为[UIView]
。这就是为什么我虽然你做不到customView.label.text
。
@anr 是的,但是所有自定义视图(UIView 子类)都是 UIView 类型。它甚至不需要转换为 UIView 即可将 CustomView 添加为子视图。这是“向上转换”-转换为超类。在这种情况下,只有向下转换(转换为子类)需要明确。因此,您可以(并且应该)按照我的回答 (@IBOutlet private var myView: CustomView!
) 中的建议以方便的方式使用属性
再读一遍答案,我觉得有问题:我希望能够做到myView.label.text
(您正在使用customView.label.text)。事实上,我试过myView.label.text
,但它不起作用。请记住,我希望能够在viewDidLoad
之外执行myView.label.text
,这意味着我只能访问myView
而不能访问customView
。
@anr 稍微改变了我的答案。确实没有必要将CustomView添加到另一个CustomView。如果 myView 是从 storyboard / xib 创建的,并且类设置为“CustomView”,那么只需在代码中将 myView 设置为此类并直接使用标签 (myView.label.text = "some text"
),根本不需要从 nib 创建视图
@anr 编辑了我对从 xib 创建的 ViewController 的答案(对于情节提要非常相似)【参考方案2】:
发布我自己的答案。
-
创建 XIB 文件。
创建 UIView 子类 Swift 文件。
在 XIB 文件所有者的识别检查器自定义类字段下,输入 UIView 子类名称(您的自定义视图)。
在 XIB 文件所有者的 Connections Inspector 下,确保 Swift 文件中的所有 IBOutlet 都已连接。
将视图添加到视图控制器并在其识别检查器自定义类类型下,指定自定义类名称。
重要: * 在您的 XIB swift 文件中,您必须正确加载 XIB 内容视图。
...
/// Initializer used by Interface Builder.
required init?(coder: NSCoder)
super.init(coder: coder)
configure()
/// Initializer used programmatically.
override init(frame: CGRect)
super.init(frame: frame)
configure()
...
func configure()
let contentView = // here use many of the functions available on the internet to
// load a view from a nib.
// Then add this view to the view hierarchy.
addSubview(contentView)
【讨论】:
以上是关于在视图控制器中访问 UIView 子类的主要内容,如果未能解决你的问题,请参考以下文章
Objective C - 从视图控制器设置 UIView 子类的标签属性
XIB 中的 UIView 子类不显示(drawRect:从未调用)