我为哪个生命周期激活和停用Swift的约束

时间:2017-07-07 17:23:09

标签: swift3 constraints lifecycle xcode8

我正在努力解决故事板中激活或停用约束的正确时间。

我制作了一个极其简化的视图控制器,显示了我遇到的这个问题。

view controller and tree

基本上,有UIView(红色框),里面是UIScrollView,最后里面是包含文本的标签。 UIScrollView距离它内部的红色UIView的所有边缘都是15。并且UILabel在其所在的UIScrollView的各个方向都是0。默认情况下,我从红色UIView的底部(称为bottomConst)到超级视图的底部有一个约束。意味着它总是相同的距离。如果没有任何改变,它将在4英寸和4.7英寸屏幕上看起来如下。这是以isActive = true启动的。

enter image description hereenter image description here

如您所见,4.7英寸屏幕上有大量空白空白。

为了解决这个问题,我添加了第二个约束来控制红色UIView的高度(称为heightConst),并以isActive = false启动。

如果UIScrollView的边界高度高于UIScrollView的contentSize高度,我使用代码在layoutIfNeeded()之后检查。如果是,则停用bottomConst并激活heightConst。问题是,而不是发生这种情况。我最终得到一个零高度的UIScrollView和一个30高的UIView,因为顶部和底部边缘约束有15个。

enter image description here

但如果我在运行它们之前手动进入并切换它们,一切看起来都是正确的。

enter image description here

这是我正在使用的代码。 (见下文) 我已经尝试将代码放在各种位置,例如viewDidLoad,viewDidAppear,viewWillLayoutSubviews,viewDidLayoutSubviews。但它们似乎都不起作用。我开始怀疑我是否应该在一个单独的生命周期中调用LayoutIfNeeded()但是有很多可能性如何做到这一点我认为我会成为那些似乎总是最了解的人。任何帮助将不胜感激。

import UIKit

class ViewController: UIViewController {

@IBOutlet var bottomConst: NSLayoutConstraint!
@IBOutlet var heightConst: NSLayoutConstraint!
@IBOutlet var scrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()


}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    scrollView.setNeedsLayout()
    scrollView.layoutIfNeeded()

    let scrollHeight = scrollView.contentSize.height

    if (scrollHeight <= scrollView.bounds.height) {
        bottomConst.isActive = false

        heightConst.constant = scrollHeight + 30
        heightConst.isActive = true

        view.layoutIfNeeded()
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

1 个答案:

答案 0 :(得分:2)

好吧,我能够找到问题的答案。但它稍微复杂,也可能取决于视图控制器的设置方式。

对于上面显示的案例,以下代码有效。

import UIKit

class ViewController: UIViewController {

@IBOutlet var bottomConst: NSLayoutConstraint!
@IBOutlet var heightConst: NSLayoutConstraint!
@IBOutlet var scrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()


}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    view.setNeedsLayout()
    view.layoutIfNeeded()

    let scrollHeight = scrollView.contentSize.height

    if (scrollHeight <= scrollView.bounds.height) {
        bottomConst.isActive = false

        heightConst.constant = scrollHeight + 30
        heightConst.isActive = true
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

结果是将viewWillAppear中的代码放在需要的位置,并将视图标记为setNeedsLayout而不是scrollView。但是我还有另外一个与我上面描述的情况非常类似的情况,除了底部约束不是超级视图,它是另一个UIView。在这种情况下,即使使用新代码,我仍然得到0高scrollView

在做了一些测试之后,我发现heightConst在我在上面的代码中设置之后仍然是真的。但是最后一次它会经过viewWillLayoutSubviewsviewDidLayoutSubviews而在那些它将再次变为虚假。我的工作是将我的代码修改为以下内容。

import UIKit

class ViewController: UIViewController {

var changeSize: Bool = false //Additional Code

@IBOutlet var bottomConst: NSLayoutConstraint!
@IBOutlet var heightConst: NSLayoutConstraint!
@IBOutlet var scrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()


}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    view.setNeedsLayout()
    view.layoutIfNeeded()

    let scrollHeight = scrollView.contentSize.height

    if (scrollHeight <= scrollView.bounds.height) {
        changeSize = true //Addition Code
        bottomConst.isActive = false

        heightConst.constant = scrollHeight + 30
        heightConst.isActive = true
    }
}

//Addition Code
override function viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if (changeSize == true && heightConst.isActive == false) {
        heightConst.isActive = true
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

但最终,我找到解决方法的方法是在每个生命周期中放置print()函数,并查看报告该约束的内容。那样的话,我可以看出它什么时候出错了。希望这对未来的其他人有所帮助!