【问题标题】:How to change the intrinsic content size through its priority如何通过其优先级更改内在内容大小
【发布时间】:2021-02-26 14:03:34
【问题描述】:

我希望第二个标签 (subview2) 保持不变,并让第一个标签 (subview1) 随着容器视图大小的减小而缩小,但无论我如何调整第二个标签仍然会缩小优先级:

import UIKit
import PlaygroundSupport

let containerView = UIView(frame: CGRect(origin: .zero, size: .init(width: 200, height: 300)))
let subview1 = UILabel()
subview1.text = "Hello"
subview1.backgroundColor = .red
containerView.addSubview(subview1)
subview1.translatesAutoresizingMaskIntoConstraints = false
let subview2 = UILabel()
subview2.text = "Hello"
subview2.backgroundColor = .cyan
containerView.addSubview(subview2)
subview2.translatesAutoresizingMaskIntoConstraints = false

let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)

subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = containerView

我试过手动增加subview2的优先级,但还是不行:

let priority1 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority1) // 750
let priority2 = subview2.contentCompressionResistancePriority(for: .horizontal)
print(priority2) // 750
subview2.setContentCompressionResistancePriority(priority2 + 100, for: .horizontal)

【问题讨论】:

    标签: ios swift autolayout nslayoutconstraint


    【解决方案1】:

    VFL(视觉格式语言)非常过时且有限。我强烈建议您改用更现代(更灵活)的语法。

    也就是说,问题出在这一行:

    let con5 = NSLayoutConstraint.constraints(withVisualFormat: 
                "H:[subview1(>=100)]-(>=30)-[subview2(>=100)]", metrics: nil, views: views)
    

    你的代码说:

    • subview1 宽度必须大于或等于100
    • subview2 宽度必须大于或等于100

    所以,setContentCompressionResistancePriority 行什么也不做。您已经说过“这些是必需的最小宽度。”

    如果您将该行更改为:

    let con5 = NSLayoutConstraint.constraints(withVisualFormat:
                "H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
    

    你应该得到你想要的结果。

    不过,您的代码使用了更现代的约束语法——您可能会发现它更合乎逻辑且更易于理解:

    NSLayoutConstraint.activate([
    
        // both labels 20-pts from containerView Top
        subview1.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
        subview2.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 20.0),
    
        // left label Leading 30-pts from containerView Leading
        subview1.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 30.0),
    
        // right label Trailing 30-pts from containerView Trailing
        subview2.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -30.0),
    
        // right label Leading at least 30-pts from left label Trailing
        subview2.leadingAnchor.constraint(greaterThanOrEqualTo: subview1.trailingAnchor, constant: 30.0),
    
    ])
    
    // don't do any of this...
    //let views: [String: Any] = ["subview1": subview1, "subview2": subview2]
    //let con1 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview1]", metrics: nil, views: views)
    //let con2 = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[subview2]", metrics: nil, views: views)
    //let con3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(30)-[subview1]", metrics: nil, views: views)
    //let con4 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview2]-(30)-|", metrics: nil, views: views)
    //let con5 = NSLayoutConstraint.constraints(withVisualFormat: "H:[subview1]-(>=30)-[subview2]", metrics: nil, views: views)
    //NSLayoutConstraint.activate(con1 + con2 + con3 + con4 + con5)
    

    编辑 -回答评论...

    如果您希望每个标签的宽度为 >= 100,但允许它们压缩(左标签首先压缩),您需要添加优先级小于 .required 的宽度约束:

    // both labels should have a width of >= 100
    let leftWidth = subview1.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
    let rightWidth = subview2.widthAnchor.constraint(greaterThanOrEqualToConstant: 100.0)
    
    // set the Priority on the width constraints to less than required
    //  to allow auto-layout to break that constraint if needed
    leftWidth.priority = .defaultHigh
    rightWidth.priority = .defaultHigh
    
    // activate the width constraints
    leftWidth.isActive = true
    rightWidth.isActive = true
    
    // tell leftLabel to compress before rightLabel
    subview1.setContentCompressionResistancePriority(UILayoutPriority.defaultLow, for: .horizontal)
    subview2.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .horizontal)
    

    【讨论】:

    • 感谢您的回答。我同意使用现代自动布局。我的方法更像是一种学术方法,以了解优先级的性质和内在内容大小以及更改它们如何影响布局。在不完全摆脱宽度常量的情况下,如何将子视图指定为“具有一定宽度但仅在容器小于给定宽度时减小尺寸”?因此,假设我最初希望每个视图获得 100 分,并且容器的优先级高于子视图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多