[英]Nested controllers + views, programmatically adding constraints, which place ? best practice?
我對布局約束/最佳實踐有多個疑問...
摘要
self.view.leadingAnchor.constraint(equalTo: parentController.view.leadingAnchor,[..])
調用self.view.leadingAnchor.constraint(equalTo: parentController.view.leadingAnchor,[..])
我的設定
在我的代碼中,我有一個像這樣的嵌套層次結構
rootController
view
menuViewController
view
menuOneViewController
view
UIButton1
UIButton2
...
UIButton6
每個級別在其父級別的錨點方面都有限制。
我首先在每個Controller的viewDidLoad方法中添加約束。
menuViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.menuOneViewController = MenuOneViewController()
guard let menuOneViewController = self.menuOneViewController else { return }
menuOneViewController.parentController = self
self.view.addSubview(menuOneViewController.view)
}
menuOneViewController:
override func viewDidLoad() {
super.viewDidLoad()
guard let parentController = self.parentController else { return }
let menuRowHeight = parentController.menuRowHeight
self.view.heightAnchor.constraint(equalToConstant: menuRowHeight).isActive = true
self.view.leadingAnchor.constraint(equalTo: parentController.view.leadingAnchor, constant: 0).isActive = true
self.view.trailingAnchor.constraint(equalTo: parentController.view.trailingAnchor, constant: 0).isActive = true
self.view.topAnchor.constraint(equalTo: parentController.view.topAnchor, constant: -(menuRowHeight)).isActive = true
通過此設置,我得到以下消息:
'Unable to activate constraint with anchors
<NSLayoutXAxisAnchor:0x600001199900 "UIView:0x7fd99e705b90.leading">
and <NSLayoutXAxisAnchor:0x600001199980 "UIView:0x7fd99e526bc0.leading">
because they have no common ancestor. Does the constraint or its
anchors reference items in different view hierarchies? That's illegal.'
我的想法和細節
而且我想我明白了……我猜想在viewDidLoad方法中還沒有建立層次結構。 我猜想它發生在viewDidLoad()之后,所以我要么需要將這些約束移到viewDidLoad之后調用的子方法中,要么可以在addSubview調用之后在父方法中創建約束。
現在,盡管后一種方法肯定可以工作,但我仍然想知道我通常會放哪個位置。 而且,我也不想讓子視圖控制器視圖應該有多大的邏輯困擾父視圖控制器。
那么我會把這樣的代碼放在updateViewConstraints
里面嗎? 因為如果這樣的話,輪換似乎沒有調用它,這是我接下來要關心的問題,還是我需要設置一些標志或執行某項操作。 手動觸發。 如果是這樣,哪種方法?在什么級別?
另外,如果該方法將被調用兩次,由於重復的約束生成/重復的約束沖突,我是否會遇到問題? 在這種情況下,最佳做法是什么?
同樣在這方面,如果我使用NSLayoutConstraint(item: view, [..]).isActive = true
與view.anchor.constraint(
我首先了解了NSLayoutConstraint,然后了解了其他方式(錨和可視格式語言),現在我混合了anchor.constraints和NSLayoutConstraint,不確定該走哪條路。 但是,由於我喜歡干凈的代碼,所以我想堅持一種方法。
首先要添加子VC
addChildViewController(child)
view.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
// set constraints here
child.didMove(toParentViewController: self)
第二個 viewDidLoad
是最合適的位置,因為旋轉會在設備旋轉時自動調整自身的布局,但是如果要進行調整,請將其作為var約束並在內部進行調整
func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {}
蘋果還建議使用錨,因為它會自動將約束添加到適當的父對象,並使用NSLayoutConstraint.activate([-,-,-,])
激活許多約束,而不是在每個對象上都添加.active = true
問題可能是在menuOneViewController
的視圖添加到menuViewController
的視圖之前調用了viewDidLoad()
。 這就是為什么得到...because they have no common ancestor
運行時錯誤。
更大的問題和解決方案是,子menuOneViewController
不應該知道該子menuOneViewController
約束的視圖。這不僅會降低組件menuOneViewController
的可重用性,而且還會使將來的調試更加困難。 在將mainOneViewController
的視圖添加為子視圖之后,應在menuViewController
中設置約束。 另外,使用NSLayoutConstraint.activate(_:)
以及.constraint(equalTo:)
不帶constant:
參數),可以節省一些空間。
這是menuViewController
的viewDidLoad()
重寫:
override func viewDidLoad() {
super.viewDidLoad()
self.menuOneViewController = MenuOneViewController()
guard let menuOneViewController = self.menuOneViewController else { return }
menuOneViewController.parentController = self
self.view.addSubview(menuOneViewController.view)
let subView = menuOneViewController.view
NSLayoutConstraint.activate(constraints: [
subView.heightAnchor.constraint(equalToConstant: menuRowHeight),
subView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor)
subView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
subView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: -menuRowHeight)
]
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.