简体   繁体   中英

Dynamic height of a UIView inside a UIStackView

Note: Similar questions have been asked on this topic but for some reason, the solutions mentioned in them doesn't seem to work for me so I'm posting this.


I have a UIScrollView that fills the entire view of a view controller and a vertical UIStackView embedded inside it.

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()
    }
}

I want to add a number of UIView subclasses ( CardView ) to this stack view. These CardView s only contain two UILabels and this view is made to resize to fit the content of these labels.

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),
        ])
    }
}

When I add these card views to the stack view, they don't seem to lay out one after the other.

在此处输入图像描述

It seems like the view is not taking the intrinsic content size of the labels when calculating the height of the view.

Any idea how to resolve this?

In your CardView you miss the detailLabel bottom anchor:

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) 
    ])
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM