在视图控制器中访问 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 子类的主要内容,如果未能解决你的问题,请参考以下文章

UIView 子类不可见

Objective C - 从视图控制器设置 UIView 子类的标签属性

XIB 中的 UIView 子类不显示(drawRect:从未调用)

iOS:使用 nib 子类化 UITableViewCell,进入 UIView(不是视图控制器)子类

子类化 UIView/UIViewController

UIView 子类不能从黑色背景更改