UIStackView分配和对齐多行UILabel

时间:2018-03-21 18:00:55

标签: ios ios11 uistackview

我正在努力解决一些基本的UIStackView分发和对齐问题。

我有一个UICollectionViewCell,它在contentView子视图中有一个水平的UIStackView。这个UIStackView有三个标签本身的垂直UIStackView,当然还有UIImageView。

这是以下屏幕截图的代码段:

    func createSubViews() {

    // contains the UIStackview with the 3 labels and the UIImageView
    containerStackView = UIStackView()
    containerStackView.axis = .horizontal
    containerStackView.distribution = .fill
    containerStackView.alignment = .top
    contentView.addSubview(containerStackView)

    // the UIStackView for the labels
    verticalStackView = UIStackView()
    verticalStackView.axis = .vertical
    verticalStackView.distribution = .fill
    verticalStackView.spacing = 10.0
    containerStackView.addArrangedSubview(verticalStackView)

    categoryLabel = UILabel()
    categoryLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
    categoryLabel.textColor = UIColor.lightGray
    verticalStackView.addArrangedSubview(categoryLabel)

    titleLabel = UILabel()
    titleLabel.numberOfLines = 3
    titleLabel.lineBreakMode = .byWordWrapping
    verticalStackView.addArrangedSubview(titleLabel)

    timeLabel = UILabel()
    timeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
    timeLabel.textColor = UIColor.lightGray
    verticalStackView.addArrangedSubview(timeLabel)

    // UIImageView
    imageView = UIImageView()
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = true
    imageView.layer.cornerRadius = 5
    layer.masksToBounds = true
    containerStackView.addArrangedSubview(imageView)
}

enter image description here

我想要的是,“时间标签”(“3天前”)总是放在每个UICollectionViewCell的底部(与UIImageView的底部对齐),而不管标题标签行的不同。

我玩过各种UIStackView发行版,限制了“时间标签”以及“标题标签”的拥抱优先级。

但无论如何我无法做对。任何提示?

2 个答案:

答案 0 :(得分:1)

更新

由于您正在设置titleLabel.numberOfLines = 3,因此一种方法是在标题文字中添加三个换行符。这将迫使titleLabel始终消耗其三行全高,迫使timeLabel到底。

也就是说,当您设置titleLabel.text时,请执行以下操作:

titleLabel.text = theTitle + "\n\n\n"

ORIGINAL

如果让其中一个标签垂直拉伸,拉伸标签的文本将在拉伸标签的边界内垂直居中,这不是您想要的。所以我们不能让标签垂直伸展。因此,我们需要引入一个可以拉伸但不可见的填充视图。

如果填充视图被压缩到零高度,堆栈视图仍然会在它之前和之后放置间距,导致titleLabeltimeLabel之间的双倍间距,你也不会这样做。 ;想要。

因此我们需要使用填充视图实现所有间距。将verticalStackView.spacing更改为0。

UIView之后padding1之后,将名为verticalStackView的通用categoryLabel添加到titleLabel。将其高度限制为等于10.

UIView之后padding2之后,将名为verticalStackView的通用titleLabel添加到timeLabel。将其高度限制在大于或等于10,以便它可以伸展。

categoryLabeltitleLabeltimeLabel的垂直拥抱优先级设置为必需,以便它们不会垂直拉伸。

verticalStackView的高度约束到containerStackView的高度,以便在需要填充可用的垂直空间时拉伸其中一个或多个已排列的子视图。唯一可以拉伸的子视图是padding2,因此它会拉伸,使标题文本靠近顶部,时间文本保持在底部。

另外,将containerStackView限制在contentView的边界并设置containerStackView.translatesAutoresizingMaskIntoConstraints = false

结果:

short title

long title

这是我的游乐场:

import UIKit
import PlaygroundSupport

class MyCell: UICollectionViewCell {

    var containerStackView: UIStackView!
    var verticalStackView: UIStackView!
    var categoryLabel: UILabel!
    var titleLabel: UILabel!
    var timeLabel: UILabel!
    var imageView: UIImageView!

    func createSubViews() {

        // contains the UIStackview with the 3 labels and the UIImageView
        containerStackView = UIStackView()
        containerStackView.axis = .horizontal
        containerStackView.distribution = .fill
        containerStackView.alignment = .top
        contentView.addSubview(containerStackView)

        // the UIStackView for the labels
        verticalStackView = UIStackView()
        verticalStackView.axis = .vertical
        verticalStackView.distribution = .fill
        verticalStackView.spacing = 0
        containerStackView.addArrangedSubview(verticalStackView)

        categoryLabel = UILabel()
        categoryLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
        categoryLabel.textColor = UIColor.lightGray
        verticalStackView.addArrangedSubview(categoryLabel)

        let padding1 = UIView()
        verticalStackView.addArrangedSubview(padding1)

        titleLabel = UILabel()
        titleLabel.numberOfLines = 3
        titleLabel.lineBreakMode = .byWordWrapping
        verticalStackView.addArrangedSubview(titleLabel)

        let padding2 = UIView()
        verticalStackView.addArrangedSubview(padding2)

        timeLabel = UILabel()
        timeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
        timeLabel.textColor = UIColor.lightGray
        verticalStackView.addArrangedSubview(timeLabel)

        // UIImageView
        imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.layer.cornerRadius = 5
        layer.masksToBounds = true
        containerStackView.addArrangedSubview(imageView)

        categoryLabel.setContentHuggingPriority(.required, for: .vertical)
        titleLabel.setContentHuggingPriority(.required, for: .vertical)
        timeLabel.setContentHuggingPriority(.required, for: .vertical)
        imageView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        containerStackView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            contentView.leadingAnchor.constraint(equalTo: containerStackView.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
            contentView.topAnchor.constraint(equalTo: containerStackView.topAnchor),
            contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
            verticalStackView.heightAnchor.constraint(equalTo: containerStackView.heightAnchor),
            padding1.heightAnchor.constraint(equalToConstant: 10),
            padding2.heightAnchor.constraint(greaterThanOrEqualToConstant: 10),
            ])
    }
}

let cell = MyCell(frame: CGRect(x: 0, y: 0, width: 320, height: 110))
cell.backgroundColor = .white
cell.createSubViews()
cell.categoryLabel.text = "MY CUSTOM LABEL"
cell.titleLabel.text = "This is my title"
cell.timeLabel.text = "3 days ago"
cell.imageView.image = UIGraphicsImageRenderer(size: CGSize(width: 110, height:110)).image { (context) in
    UIColor.blue.set()
    UIRectFill(.infinite)
}

PlaygroundPage.current.liveView = cell

答案 1 :(得分:0)

问题是垂直堆栈视图。你显然想说:中间标签的顶部应该拥抱MyCustomLabel底部,但3天前底部应该拥抱整体底部。这不是你可以对堆栈视图说的。

即使这不是您想要说的,您仍然需要使垂直堆栈视图占据单元格的整个高度,您将如何做到这一点?在您展示的代码中,您根本不会这样做;实际上,您的堆栈视图基于该代码具有零大小,这将导致各种问题。

因此,我建议您只需删除所有堆栈视图,然后直接配置布局。您的布局很容易使用自动布局约束进行配置。