【问题标题】:Custom UIView is blank when instantiated from a XIB in Swift 4从 Swift 4 中的 XIB 实例化时,自定义 UIView 为空白
【发布时间】:2023-03-19 04:10:01
【问题描述】:

我有一个自定义视图,我正尝试从自定义 XIB 加载,但加载时视图显示为空白,即使在调试时认为它具有正确的大小。

我的调试语句显示框架的大小正确:

commonInit()
XIB:MyCustomView
myView 帧:(0.0, 0.0, 320.0,568.0)
myView ContentSize: (320.0, 710.0)

这是我用来调用自定义视图的自定义 VC

class MyCustomViewController: UIViewController {

    var myView : MyCustomView!

    override func viewDidLoad() {
        super.viewDidLoad()

        myView = MyCustomView(frame: self.view.frame)

        self.view.addSubview(myView)

        updateScrollViewSize()

        print("myView Frame: \(myView.frame)")
        print("myView ContentSize: \(myView.contentView.contentSize)")

    }

    func updateScrollViewSize () {
        var contentRect = CGRect.zero
        for view in myView.contentView.subviews {
            contentRect = contentRect.union(view.frame)
        }
        myView.contentView.contentSize = CGSize(width: myView.contentView.frame.size.width, height: contentRect.size.height + 5)
    }
}

有一个XIB,其文件所有者为MyCustomView,并且所有出口都正确连接。

class MyCustomView: UIView {

     let kCONTENT_XIB_NAME = "MyCustomView"

    @IBOutlet var contentView: UIScrollView!

    @IBOutlet weak var lbl_datein: UILabel!
    //.. A bunch of other GUI elements for the scrollview
    @IBOutlet weak var text_location: UITextField!


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

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

    func commonInit() {
        print(#function)
        print("XIB: \(kCONTENT_XIB_NAME)")

        Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
        contentView.addSubview(self)
        contentView.frame = self.bounds
        contentView.backgroundColor = .blue
    }
}

有没有人看到我在尝试加载视图时做错了什么

【问题讨论】:

  • 我试过了,setNeedsLayout 没用。
  • 基本上,你想要self.addSubview(contentView),而不是相反。

标签: ios swift storyboard xib nib


【解决方案1】:

我将使用扩展程序发布您所做的替代方案。

extension UIView {

    @discardableResult
    func fromNib<T : UIView>(_ nibName: String? = nil) -> T? {
        let bundle = Bundle(for: type(of: self))
        guard let view = bundle.loadNibNamed(nibName ?? String(describing: type(of: self)), owner: self, options: nil)?[0] as? T else {
            return nil
        }
        view.translatesAutoresizingMaskIntoConstraints = false

        self.addSubview(view)
        view.autoPinEdgesToSuperviewEdges()
        return view
    }
}

*请注意,我使用 PureLayout 是为了方便的自动布局管理,如果您不使用 PureLayout,您可以自己手动应用约束。

使用上面所有你需要做的就是从你的 init 中调用下面的代码;

fromNib()

*最后一点。自定义视图名称必须与 nib 名称匹配,否则您必须将 nib 名称传递给 fromNib 函数。

你现在有了更可重用的东西。

【讨论】:

  • 我不能使用 PureLayout。
  • 没关系,您可以手动应用这些约束,或者您可以推出自己的扩展,提供方便的方法来做到这一点。
  • 或者你可以使用自动调整掩码[.flexibleWidth, .flexibleHeight]
【解决方案2】:

我无法让它运行复制/粘贴代码。也许缺少一些设置,但我很难理解它应该如何工作。问题中的原始代码在此行崩溃:

contentView.addSubview(self)

因为当您拥有IBOutlets 时,如果您使用MyCustomView(frame: self.view.frame) 对其进行初始化,它们将始终为nil。它必须调用initWithCoder 函数。

这里发生了很多事情,但我会这样做:

class MyCustomViewController: UIViewController {

    var myView: MyCustomView!

    override func viewDidLoad() {
        super.viewDidLoad()

        myView = Bundle.main.loadNibNamed("MyCustomView", owner: self, options: nil)?.first as? MyCustomView

        self.view.addSubview(myView)

        updateScrollViewSize()

        print("myView Frame: \(myView.frame)")
        print("myView ContentSize: \(myView.contentView.contentSize)")

    }

    func updateScrollViewSize () {
        var contentRect = CGRect.zero
        for view in myView.contentView.subviews {
            contentRect = contentRect.union(view.frame)
        }
        myView.contentView.contentSize = CGSize(width: myView.contentView.frame.size.width, height: contentRect.size.height + 5)
    }

}

class MyCustomView: UIView {

    let kCONTENT_XIB_NAME = "MyCustomView"

    @IBOutlet var contentView: UIScrollView!

    @IBOutlet weak var lbl_datein: UILabel!
    //.. A bunch of other GUI elements for the scrollview
    @IBOutlet weak var text_location: UITextField!

}

我假设 nib 中的顶级对象属于 MyCustomView 类,这会导致很多奇怪的事情。 loadNibNamed 将调用 init?(coder aDecoder: NSCoder),因此理想情况下,您首先从视图控制器调用它,而不是从自定义视图对象。

关于“无法将自己添加为子视图”错误,我在运行时没有看到该错误,但我从这一行中期待它:

contentView.addSubview(self)

因为这正是它的作用,所以将self 添加为已经是self 子视图的视图的子视图。

【讨论】:

    【解决方案3】:

    如果我的替代答案太多,让我尝试解决您现有的问题。而不是下面的;

    Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
    contentView.addSubview(self)
    

    试试;

    let nibView = Bundle.main.loadNibNamed(kCONTENT_XIB_NAME, owner: self, options: nil)
    self.addSubView(nibView)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-15
      • 2018-06-15
      • 2014-10-20
      • 2015-04-17
      • 1970-01-01
      • 2017-10-01
      • 2015-11-27
      • 1970-01-01
      相关资源
      最近更新 更多