如何向从nib文件加载的子视图添加约束?

时间:2017-11-14 23:24:33

标签: ios swift autolayout

我试图从nib文件中将子视图加载到我的应用的每个页面。现在,我正在使用一种不同寻常的方法加载这个子视图,因为我通过UIStoryboard的扩展来做这件事(可能与我的问题无关,但我不确定)。这就是加载nib文件时代码的外观:

extension UIStoryboard {
    public func appendCustomView(to viewController: UIViewController) {
        if let myCustomSubview = Bundle.main.loadNibNamed("MyCustomSubview", owner: nil, options: nil)![0] as? MyCustomSubview {
            viewController.view.addSubview(myCustomSubview)
        }
    }
}

此代码执行它应该执行的操作并添加" MyCustomSubview"到视图控制器(我不会详细了解这个方法是如何被调用的,因为它起作用所以它看起来并不重要)。问题是我不能为我的生活找出如何添加影响myCustomSubview大小的约束。我已经尝试将代码放在我上面显示的函数以及MyCustomSubview swift文件中以添加约束,但无论我做什么,子视图都不会改变。

理想情况下,约束会固定" MyCustomSubview"在ViewController的底部,宽度设置为屏幕大小和硬编码高度约束。

以下是我尝试过的两种主要方法(每种方法大约有100种不同的方法),但不起作用:

方法1 - 直接从" appendCustomView"

添加约束
public func appendCustomView(to viewController: UIViewController) {
    if let myCustomSubview = Bundle.main.loadNibNamed("MyCustomSubview", owner: nil, options: nil)![0] as? MyCustomSubview {

        let top = NSLayoutConstraint(item: myCustomSubview, attribute: .top, relatedBy: .equal
        , toItem: viewController.view, attribute: .top, multiplier: 1, constant: 50.0)

        viewController.view.addSubview(myCustomSubview)
        viewController.view.addConstraint(top)
    }
}

方法2 - 在MyCustomSubview中添加约束出口和setter方法

class MyCustomSubview: UIView {
    @IBOutlet weak var widthConstraint: NSLayoutConstraint!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    func setConstraints(){
        self.widthConstraint.constant = UIScreen.main.bounds.size.width
        self.heightConstraint.constant = 20
    }
}

在" appendCustomView"

中调用setter方法
public func appendCustomView(to viewController: UIViewController) {
    if let myCustomSubview = Bundle.main.loadNibNamed("MyCustomSubview", owner: nil, options: nil)![0] as? MyCustomSubview {

        myCustomSubview.setConstraints()
        viewController.view.addSubview(myCustomSubview)
    }
}

(*注意:这些例子的实际限制是无关紧要的,我没有尝试满足上面提到的规范,我只是试图对视图进行任何改变,以了解约束是更新。他们不是。)

编辑:更改" MyCustomNib"到" MyCustomSubview"为清楚起见。

3 个答案:

答案 0 :(得分:2)

当您从Nib向视图添加约束时,您必须调用yourView.translatesAutoresizingMaskIntoConstraints = false,并且还需要确保您拥有全部4(除非它是标签或其他一些仅需要的视图类型2)制约因素:

以下是一些示例代码,使视图填充其父视图:

        parentView.addSubview(yourView)

        yourView.translatesAutoresizingMaskIntoConstraints = false

        yourView.topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
        yourView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
        yourView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor).isActive = true
        yourView.trailingAnchor.constraint(equalTo: parentView.trailingAnchor).isActive = true

编辑:我实际上已经开始使用这种添加NSLayoutConstraints的方法,即使结果相同

NSLayoutConstraint.activate([
            yourView.topAnchor.constraint(equalTo: parentView.topAnchor),
            yourView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
            yourView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor),
            yourView.trailingAnchor.constraint(equalTo: parentView.trailingAnchor),
])

答案 1 :(得分:0)

对于将来遇到此问题的任何人来说,这是我通过稍微调整this answer来提出的解决方案

在与nib文件对应的swift类中添加setConstraints(withRelationshipTo)方法:

class MyCustomSubview: UIView {

    func setConstraints(withRelationshipTo view: UIView){
        self.translatesAutoresizingMaskIntoConstraints = false

        // Replace with your own custom constraints
        self.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
        self.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        self.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        self.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    }
}

然后在将nib文件添加到视图后调用setConstraints方法(可能在视图控制器的viewWillAppear或viewDidLoad中)

class MyViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool){
        super.viewWillAppear(animated)
        if let myCustomSubview = Bundle.main.loadNibNamed("MyCustomSubview", owner: nil, options: nil)![0] as? MyCustomSubview {
            let view = self.view  // Added for clarity
            view.addSubview(myCustomSubview)
            myCustomSubview.setConstraints(withRelationshipTo: view)
        } 
    }
}

答案 2 :(得分:0)

您可以将此扩展程序用于您将子视图添加到现有UIView的任何位置。

extension UIView {

  func setConstraintsFor(contentView: UIView, left: Bool = true, top: Bool = true, right: Bool = true, bottom: Bool = true) {

      contentView.translatesAutoresizingMaskIntoConstraints = false
      self.addSubview(contentView)

      var constraints         : [NSLayoutConstraint] = []
      if left {
          let constraintLeft      = NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0)
          constraints.append(constraintLeft)
      }

      if top {
          let constraintTop       = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
          constraints.append(constraintTop)
      }

      if right {
          let constraintRight     = NSLayoutConstraint(item: contentView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0)
          constraints.append(constraintRight)
      }

      if bottom {
          let constraintBottom    = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
          constraints.append(constraintBottom)
      }

      self.addConstraints(constraints)
  }
}

您可以这样调用此方法:

containerView.setConstraintsFor(contentView: subView!, top: false)

这会将subView添加到containerView并将约束添加到除了顶边之外的所有边。 如果需要,可以修改此方法以传递left,top,right,bottom常量值。