2017-06-16 61 views
1

边使用操场UIStackView玩编程包含两个标签,我意识到,这样我做的堆栈视图和标签不自动计算其大小。那是我的(丑陋的)代码:UIStackView - 自动计算理想的尺寸根据儿童

import UIKit 

let label1 = UILabel() 
let label2 = UILabel() 
let arrangedViews: [UIView] = [label1, label2] 
let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) 

label1.text = "Text 1" 
label2.text = "Text 2" 

for case let label as UILabel in arrangedViews { 
    label.textColor = .white 
    label.sizeToFit() 
} 

view.backgroundColor = .black 
let stackView = UIStackView(arrangedSubviews: arrangedViews) 
stackView.axis = .vertical 
stackView.distribution = .fill 
stackView.layer.borderColor = UIColor.white.cgColor 
stackView.layer.borderWidth = 1 

var stackViewIdealSize = CGSize() 
stackViewIdealSize.width = label1.intrinsicContentSize.width 

arrangedViews.forEach{label in stackViewIdealSize.height += label.intrinsicContentSize.height} 
stackView.frame.size = stackViewIdealSize 

view.addSubview(stackView) 

此代码,除了是巨大的做这样一个“简单的事情”,还算大小不正确的方式,我的操场的看法是这样的:

enter image description here

有没有一种方法,使UIStackView甚至UIView s到更智能地计算理想的尺寸是多少?

回答

3

我从设定惊讶你得到任何效果堆栈视图的borderColorborderWidthUIStackView是记录为“a nonrendering subclass of UIView; that is, it does not provide any user interface of its own.”事实上它使用CATransformLayer作为其层和CATransformLayer文档说“The CALayer properties that are rendered by a layer are ignored, including: backgroundColor, contents, border style properties, stroke style properties, etc.”。迫使其布置子视图

无论如何,因为其alignment.fill,堆叠视图中创建所需优先级的约束是相同的宽度本身。以下是这些限制:

<NSLayoutConstraint:0x60800008c210 'UISV-alignment' UILabel:0x7f821e4023d0'Text 1'.leading == UILabel:0x7f821e608ef0'Text 2'.leading (active)> 
<NSLayoutConstraint:0x60800008c2b0 'UISV-alignment' UILabel:0x7f821e4023d0'Text 1'.trailing == UILabel:0x7f821e608ef0'Text 2'.trailing (active)> 
<NSLayoutConstraint:0x60800008c080 'UISV-canvas-connection' UIStackView:0x7f821e40b790.leading == UILabel:0x7f821e4023d0'Text 1'.leading (active)> 
<NSLayoutConstraint:0x60800008c1c0 'UISV-canvas-connection' H:[UILabel:0x7f821e4023d0'Text 1']-(0)-| (active, names: '|':UIStackView:0x7f821e40b790)> 

每个子视图设置标签本身具有约束自己的宽度设置为它的内在宽度。但是,此约束默认情况下为而不是必需优先级。以下是这些限制:

<NSContentSizeLayoutConstraint:0x6080000b7a00 UILabel:0x7fe385601720'Text 1'.width == 44.5 Hug:250 CompressionResistance:750 (active)> 
<NSContentSizeLayoutConstraint:0x6180000abac0 UILabel:0x7fb809d0d810'Text 2'.width == 47 Hug:250 CompressionResistance:750 (active)> 

这个约束有两个优先事项(“拥抱”和“CompressionResistance”)。两者都低于要求的优先级。 (所需的优先权是1000)

在没有其他更高优先级的约束,这些约束将使堆栈视图正好足够宽,以适应其最宽布置子视图。

您省略了关键的一步是,你没有设置stackView.translatesAutoresizingMaskIntoConstraints = false。因为您没有将其设置为false,所以堆栈视图具有必需优先级约束,将其位置和大小设置为其现有的frame。您可以设置其现有frame.size.width到“文本1”的标签的固有宽度,但比“文本2”标签的固有宽度窄。所以堆栈视图给自己一个必需优先的宽度约束,反过来也控制了“文本2”标签的宽度,迫使其宽度比其内在宽度窄,所以它剪切文本。下面是一个约束:

<NSLayoutConstraint:0x60800009a6d0 'UIView-Encapsulated-Layout-Width' UIStackView:0x7fb125c059d0.width == 44.5 (active)> 

通过关闭translatesAutoresizingMaskIntoConstraints,你告诉堆栈视图创建约束匹配现有的框架。如果您使用约束来设置堆栈视图的位置,但不是其大小,其他约束(如前所述)将能够将其大小设置为适合其排列的子视图。

因此,这里是我怎么会写操场:

import UIKit 
import PlaygroundSupport 

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) 
view.backgroundColor = #colorLiteral(red: 0.9568627477, green: 0.6588235497, blue: 0.5450980663, alpha: 1) 
PlaygroundPage.current.liveView = view 

let stackView = UIStackView() 
stackView.translatesAutoresizingMaskIntoConstraints = false 
stackView.axis = .vertical 

for i in 1 ... 2 { 
    let label = UILabel() 
    label.text = "Text \(i)" 
    label.textColor = .white 
    stackView.addArrangedSubview(label) 
} 

view.addSubview(stackView) 
view.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true 
view.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true 

勾勒出堆栈视图,我们可以添加另一种观点认为:

let stackOutlineView = UIView() 
stackOutlineView.translatesAutoresizingMaskIntoConstraints = false 
stackOutlineView.backgroundColor = .clear 
stackOutlineView.layer.borderWidth = 1 
stackOutlineView.layer.borderColor = UIColor.black.cgColor 
view.addSubview(stackOutlineView) 
stackView.leadingAnchor.constraint(equalTo: stackOutlineView.leadingAnchor).isActive = true 
stackView.trailingAnchor.constraint(equalTo: stackOutlineView.trailingAnchor).isActive = true 
stackView.topAnchor.constraint(equalTo: stackOutlineView.topAnchor).isActive = true 
stackView.bottomAnchor.constraint(equalTo: stackOutlineView.bottomAnchor).isActive = true 

这里的结果:

playground result

+0

令人惊叹的解释。 – juniorgarcia