根据最大的子视图使用自动布局调整超级视图的大小
Posted
技术标签:
【中文标题】根据最大的子视图使用自动布局调整超级视图的大小【英文标题】:Resize superview with autolayout depending on largest subview 【发布时间】:2015-07-14 07:41:16 【问题描述】:如果我们有具有动态高度的内部NSView
列,使用自动布局调整超级视图大小的最佳做法是什么?
例如。如果我们有两列布局,其中左列高度大于右列,则超级视图高度应与右列高度相同。比,如果我们将右列高度更改为大于左列高度,则超级视图高度应更改为右列的高度。如何做到这一点?
我做了一个示例项目来测试这个:
-
最初我们有两列的布局,其中左侧
NSView
的.Bottom
约束附加到超级视图的底部。
-
如果我们按下
Make Right Bigger
按钮,我会让右边NSView
的高度大于左边。
所以我希望在这里 superview 根据更大的列(右列)改变高度。这样做有什么好的做法吗?
代码:
import Cocoa
class ViewController: NSViewController
let leftView = NSView()
let rightView = NSView()
let button = NSButton()
var rightViewHeightConstraint: NSLayoutConstraint?
override func loadView()
self.view = TestView()
override func viewDidLoad()
super.viewDidLoad()
leftView.backgroundColor = NSColor.redColor()
rightView.backgroundColor = NSColor.orangeColor()
layoutLeft(view, insertView: leftView)
layoutRight(view, insertView: rightView)
button.title = "Make Right Bigger"
button.target = self
button.action = "makeBigger:"
ViewControllerLayout.layoutBotton(view, insertView: button, bottom: -20)
func makeBigger(sender: AnyObject)
rightViewHeightConstraint?.animator().constant = 150.0
func layoutLeft(containerView: NSView, insertView: NSView)
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
let c1 = NSLayoutConstraint(item: insertView, attribute: .Left, relatedBy: .Equal, toItem: containerView, attribute: .Left, multiplier: 1.0, constant: 0.0)
let c2 = NSLayoutConstraint(item: insertView, attribute: .Width, relatedBy: .Equal, toItem: containerView, attribute: .Width, multiplier: 0.5, constant: 0.0)
let c3 = NSLayoutConstraint(item: insertView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100.0)
let c4 = NSLayoutConstraint(item: insertView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let c5 = NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: -60.0)
containerView.addConstraint(c1)
containerView.addConstraint(c2)
containerView.addConstraint(c3)
containerView.addConstraint(c4)
containerView.addConstraint(c5)
func layoutRight(containerView: NSView, insertView: NSView)
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
let c1 = NSLayoutConstraint(item: insertView, attribute: .Right, relatedBy: .Equal, toItem: containerView, attribute: .Right, multiplier: 1.0, constant: 0.0)
let c2 = NSLayoutConstraint(item: insertView, attribute: .Width, relatedBy: .Equal, toItem: containerView, attribute: .Width, multiplier: 0.5, constant: 0.0)
let c3 = NSLayoutConstraint(item: insertView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50.0)
let c4 = NSLayoutConstraint(item: insertView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let c5 = NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: -60.0)
containerView.addConstraint(c1)
containerView.addConstraint(c2)
containerView.addConstraint(c3)
containerView.addConstraint(c4)
// containerView.addConstraint(c5) // Cant add .Bottom constraint here, because of different column sizes.
rightViewHeightConstraint = c3
struct ViewControllerLayout
static func layoutBotton(containerView: NSView, insertView: NSView, bottom: Double)
insertView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(insertView)
containerView.addConstraint(NSLayoutConstraint(item: insertView, attribute: .CenterX, relatedBy: .Equal, toItem: containerView, attribute: .CenterX, multiplier: 1.0, constant: 0.0))
containerView.addConstraint(NSLayoutConstraint(item: insertView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: CGFloat(bottom)))
下载测试项目:GitHub
【问题讨论】:
当视图高度改变时你会收到回调吗? 一种方法是为列视图注册NSNotificationCenter.defaultCenter().addObserver(self, selector: "viewDidResize:", name: NSViewFrameDidChangeNotification, object: self)
通知。比我可以手动计算和更改超级视图的高度。但也许可以仅通过约束重新创建这种行为?
【参考方案1】:
仅在约束条件下设法完成此任务。刚刚添加了列的容器视图并将其高度设置为GreaterThanOrEqual
到左列和右列。
view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Height, relatedBy: .GreaterThanOrEqual, toItem: leftView, attribute: .Height, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Height, relatedBy: .GreaterThanOrEqual, toItem: rightView, attribute: .Height, multiplier: 1, constant: 0))
【讨论】:
【参考方案2】:首先在superview上创建一个带高度的约束
let heightConstraint = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: greaterHeightAmongTwoColumns)
正如评论中所讨论的,您可以发布通知,然后让超级视图知道更新的框架。超级视图将检查两列中任何一个的更新高度是否大于其当前高度并更新其上面声明的 heightConstraint 然后调用
[self layoutIfNeeded]
在超级视图的超级视图上,以便它与新框架一起布局。
【讨论】:
以上是关于根据最大的子视图使用自动布局调整超级视图的大小的主要内容,如果未能解决你的问题,请参考以下文章