【问题标题】:accessing UIView subclass in view controller在视图控制器中访问 UIView 子类
【发布时间】: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/…你可能会找到问题的答案

标签: ios swift uiview uiviewcontroller


【解决方案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】:

发布我自己的答案。

  1. 创建 XIB 文件。
  2. 创建 UIView 子类 Swift 文件。
  3. 在 XIB 文件所有者的识别检查器自定义类字段下,输入 UIView 子类名称(您的自定义视图)。
  4. 在 XIB 文件所有者的 Connections Inspector 下,确保 Swift 文件中的所有 IBOutlet 都已连接。
  5. 将视图添加到视图控制器并在其识别检查器自定义类类型下,指定自定义类名称。

重要: * 在您的 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)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 2013-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多