UIStackView 中 UIView 的动态高度

Dynamic height of a UIView inside a UIStackView

注意:有人就此主题提出了类似的问题,但出于某种原因,其中提到的解决方案似乎对我不起作用,所以我发布了这个。


我有一个 UIScrollView 填充视图控制器的整个视图和一个嵌入其中的垂直 UIStackView

class ViewController: UIViewController {
    private let scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.showsVerticalScrollIndicator = false
        return scrollView
    }()
    lazy private var cardsStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.spacing = 8
        stackView.distribution = .fill
        return stackView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .secondarySystemBackground
        
        view.addSubview(scrollView)
        scrollView.addSubview(cardsStackView)
        let padding: CGFloat = 10
        NSLayoutConstraint.activate([
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: padding),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
            scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -padding),
            
            cardsStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            cardsStackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            cardsStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            cardsStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
            cardsStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
        ])
        
        addCardViews()
    }
}

我想向这个堆栈视图中添加一些 UIView 个子类 (CardView)。这些 CardView 仅包含两个 UILabels,此视图会调整大小以适合这些标签的内容。

class CardView: UIView {
    lazy private var titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
        return label
    }()
    lazy private var detailLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
        label.numberOfLines = 0
        return label
    }()
    
    init(title: String, details: String) {
        super.init(frame: .zero)
        titleLabel.text = title
        detailLabel.text = details
        commonInit()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        backgroundColor = .systemGreen
        
        layoutViews()
    }
    
    private func layoutViews() {
        translatesAutoresizingMaskIntoConstraints = false
        
        addSubview(titleLabel)
        addSubview(detailLabel)
        NSLayoutConstraint.activate([
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            titleLabel.topAnchor.constraint(equalTo: topAnchor),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
            
            detailLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 6),
            detailLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
        ])
    }
}

当我将这些卡片视图添加到堆栈视图时,它们似乎并没有一个接一个地布局。

在计算视图高度时,视图似乎没有采用标签的固有内容大小。

知道如何解决这个问题吗?

在您的 CardView 中您错过了 detailLabel 底部锚点:

private func layoutViews() {
    translatesAutoresizingMaskIntoConstraints = false
    
    addSubview(titleLabel)
    addSubview(detailLabel)
    NSLayoutConstraint.activate([
        titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
        titleLabel.topAnchor.constraint(equalTo: topAnchor),
        titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
        
        detailLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
        detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 6),
        detailLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
        // This is missing 
        detailLabel.bottomAnchor.constraint(equalTo: bottomAnchor) 
    ])
}