2017-07-07 53 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()功能在每個生命週期,看看它報告說,約束了。這樣,我可以看到它什麼時候出錯了。希望這可以幫助未來的其他人!