2017-07-07 26 views
1

我正在努力争取在故事板中激活或停用约束的正确时间。哪些生命周期可以激活和关闭Swift的约束条件

我做了一个非常简化的视图控制器,显示我遇到的这个问题。

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和一个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. 
} 
} 
+0

你做错了。使层次结构成为滚动视图 - 视图 - 标签。使视图与标签尺寸相同。你完成了,不需要更新约束。 – Sulthan

+0

我在想你在这里提出的建议。我想我会指出我查看> scrollview>标签的原因。我正在使用视图作为颜色背景,并且四舍五入。否则,我只是有scrollview>标签。但即使我提出了你的建议,我想我仍然会遇到同样的问题。我不得不将scrollview限制为一个大小,这意味着我可以再次以空白结尾,或者比viewController高的scrollview。但是,谢谢你的建议。 –

回答

1

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

对于我上面显示的情况下面的代码工作。

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()功能在每个生命周期,看看它报告说,约束了。这样,我可以看到它什么时候出错了。希望这可以帮助未来的其他人!