我正在努力解决故事板中激活或停用约束的正确时间。
我制作了一个极其简化的视图控制器,显示了我遇到的这个问题。
基本上,有UIView(红色框),里面是UIScrollView,最后里面是包含文本的标签。 UIScrollView距离它内部的红色UIView的所有边缘都是15。并且UILabel在其所在的UIScrollView的各个方向都是0。默认情况下,我从红色UIView的底部(称为bottomConst)到超级视图的底部有一个约束。意味着它总是相同的距离。如果没有任何改变,它将在4英寸和4.7英寸屏幕上看起来如下。这是以isActive = true
启动的。
如您所见,4.7英寸屏幕上有大量空白空白。
为了解决这个问题,我添加了第二个约束来控制红色UIView的高度(称为heightConst),并以isActive = false
启动。
如果UIScrollView的边界高度高于UIScrollView的contentSize高度,我使用代码在layoutIfNeeded()
之后检查。如果是,则停用bottomConst并激活heightConst。问题是,而不是发生这种情况。我最终得到一个零高度的UIScrollView和一个30高的UIView,因为顶部和底部边缘约束有15个。
但如果我在运行它们之前手动进入并切换它们,一切看起来都是正确的。
这是我正在使用的代码。 (见下文) 我已经尝试将代码放在各种位置,例如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.
}
}
答案 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
在我在上面的代码中设置之后仍然是真的。但是最后一次它会经过viewWillLayoutSubviews
和viewDidLayoutSubviews
而在那些它将再次变为虚假。我的工作是将我的代码修改为以下内容。
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()
函数,并查看报告该约束的内容。那样的话,我可以看出它什么时候出错了。希望这对未来的其他人有所帮助!