UIStackView 的子视图具有固有大小,但仍然忽略包含优先级的内容

Posted

技术标签:

【中文标题】UIStackView 的子视图具有固有大小,但仍然忽略包含优先级的内容【英文标题】:UIStackView's subviews have intrinsic size, yet still ignore content hugging priorities 【发布时间】:2020-07-09 22:40:16 【问题描述】:

我正在尝试以编程方式创建一个具有填充分布的堆栈视图,允许我选择拉伸哪些子视图以填充额外空间,但到目前为止我似乎无法控制哪个视图正在扩展。

class ShelfVC: UIViewController 

    let shelfContentView = UIStackView()
    
    override func viewDidLoad() 
        super.viewDidLoad()

        view.addSubview(shelfContentView)
        shelfContentView.translatesAutoresizingMaskIntoConstraints = false
        shelfContentView.layoutEqualTo(view: view)
        shelfContentView.spacing = 16

        shelfContentView.isLayoutMarginsRelativeArrangement = true
        let shelfMargin = CGFloat(16)
        shelfContentView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: shelfMargin, leading: shelfMargin, bottom: shelfMargin, trailing: shelfMargin)
        
        createTestBlocks()
    

    func createTestBlocks() 

            let view1 = UIView()
            shelfContentView.addArrangedSubview(view1)
            view1.widthAnchor.constraint(equalToConstant: 100).isActive = true
            view1.backgroundColor = .systemRed
            view1.setContentHuggingPriority(.defaultHigh, for: .horizontal)

            let view2 = UIView()
            shelfContentView.addArrangedSubview(view2)
            view2.widthAnchor.constraint(equalToConstant: 100).isActive = true
            view2.backgroundColor = .systemPurple
            view2.setContentHuggingPriority(.defaultLow, for: .horizontal)
            
            let view3 = UIView( )
            shelfContentView.addArrangedSubview(view3)
            view3.widthAnchor.constraint(equalToConstant: 100).isActive = true
            view3.backgroundColor = .systemBlue
            view3.setContentHuggingPriority(.defaultHigh, for: .horizontal)
    

我期待看到这个:

但是,相反,我看到了:

为什么蓝色视图的拥抱优先级高于紫色视图时会拉伸?

【问题讨论】:

【参考方案1】:

Content Hugging Priority 与 Constraint Priority 不同,且 Constraints 不定义 Intrinsic Content Size。

内容拥抱(和内容压缩阻力)优先级基于内在内容大小。

您已经给每个视图一个 Width 约束,而您的堆栈视图正在使用它来开始 安排。然后它打破其中一个约束,因为它不能满足所有约束。

你有两个选择:

约束不同的优先级 给视图一个固有内容大小并设置拥抱优先级

这是第一个例子:

class ConstraintHuggingShelfVC: UIViewController 
    
    let shelfContentView = UIStackView()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        view.addSubview(shelfContentView)
        shelfContentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            
            shelfContentView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0),
            shelfContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
            shelfContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0),
            shelfContentView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0),
            
        ])
        
        //shelfContentView.layoutEqualTo(view: view)
        shelfContentView.spacing = 16
        
        shelfContentView.isLayoutMarginsRelativeArrangement = true
        let shelfMargin = CGFloat(16)
        shelfContentView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: shelfMargin, leading: shelfMargin, bottom: shelfMargin, trailing: shelfMargin)
        
        createTestBlocks()
    
    
    func createTestBlocks() 
        
        let view1 = UIView()
        shelfContentView.addArrangedSubview(view1)
        view1.backgroundColor = .systemRed

        let wc1 = view1.widthAnchor.constraint(equalToConstant: 100)
        wc1.isActive = true
        wc1.priority = .defaultHigh

        let view2 = UIView()
        shelfContentView.addArrangedSubview(view2)
        view2.backgroundColor = .systemPurple

        let wc2 = view2.widthAnchor.constraint(equalToConstant: 100)
        wc2.isActive = true
        wc2.priority = .defaultLow

        let view3 = UIView( )
        shelfContentView.addArrangedSubview(view3)
        view3.backgroundColor = .systemBlue
        
        let wc3 = view3.widthAnchor.constraint(equalToConstant: 100)
        wc3.isActive = true
        wc3.priority = .defaultHigh
        
    

这是第二个例子:

class IntrinsicView: UIView 
    var myIntrinsicSize: CGSize = .zero
    override var intrinsicContentSize: CGSize 
        return myIntrinsicSize
    


class IntrisicSizeShelfVC: UIViewController 
    
    let shelfContentView = UIStackView()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        view.addSubview(shelfContentView)
        shelfContentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            
            shelfContentView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0),
            shelfContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
            shelfContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0),
            shelfContentView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0),
            
        ])

//      shelfContentView.layoutEqualTo(view: view)
        shelfContentView.spacing = 16
        
        shelfContentView.isLayoutMarginsRelativeArrangement = true
        let shelfMargin = CGFloat(16)
        shelfContentView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: shelfMargin, leading: shelfMargin, bottom: shelfMargin, trailing: shelfMargin)
        
        createTestBlocks()
    
    
    func createTestBlocks() 
        
        let view1 = IntrinsicView()
        shelfContentView.addArrangedSubview(view1)
        view1.backgroundColor = .systemRed

        view1.myIntrinsicSize = CGSize(width: 100, height: 0)
        view1.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        
        let view2 = IntrinsicView()
        shelfContentView.addArrangedSubview(view2)
        view2.backgroundColor = .systemPurple

        view2.myIntrinsicSize = CGSize(width: 100, height: 0)
        view2.setContentHuggingPriority(.defaultLow, for: .horizontal)
        
        let view3 = IntrinsicView( )
        shelfContentView.addArrangedSubview(view3)
        view3.backgroundColor = .systemBlue

        view3.myIntrinsicSize = CGSize(width: 100, height: 0)
        view3.setContentHuggingPriority(.defaultHigh, for: .horizontal)
    

两者都产生相同的布局:

【讨论】:

【参考方案2】:

UIStackView 根据内容压缩优先级使用.fill 收缩和扩展,如果排列的子视图没有填满堆栈视图。因此,请尝试将 setContentHuggingPriority 更改为 setContentCompressionResistancePriority

有关UIStackView.Distribution.fill 属性的更多信息,请参阅https://developer.apple.com/documentation/uikit/uistackview/distribution/fill。

【讨论】:

您的意思是尝试将setContentHuggingPriority 更改为setContentCompressionResistancePriority

以上是关于UIStackView 的子视图具有固有大小,但仍然忽略包含优先级的内容的主要内容,如果未能解决你的问题,请参考以下文章

防止 UIStackView 中的内在内容大小

如何在 Xcode 中调整 UIStackView 的子视图大小?

当 UIStackView 更改其排列的子视图时,UITableViewCell 不会调整大小

systemLayoutSizeFitting 忽略布局约束并使用图像视图固有大小

UIStackView 图层属性

如何用你的不同尺寸的子视图制作 UIStackView?