iOS - 在水平 UIStackView 中获取所有可用的 space

iOS - Take all the available space in a horizontal UIStackView

我有 UITableViewCell,其中包含水平 UIStackViewUIStackView 按以下顺序包含四个视图。

UIImageView   UILabel    UILabel UIImageView

arrangedSubViews后有16 points个间距。我希望第二个 UILabel 占用所有可用的 space。如果没有足够的 space,文本应该换行。

我使用了以下代码。它几乎可以工作。问题是即使 UILabel 之间有足够的 space,正如您在所附的屏幕截图中看到的那样,第二个 UILabel 会中断。但我希望它只有在没有足够的情况下才会中断 space.


class TableViewCell: UITableViewCell {
    
    static let identifier = "TableViewCell"
    
    private let leadingImageView: UIImageView = {
        let view = UIImageView(image: UIImage(systemName: "calendar"))
        view.setConstraints(heightConstant: 25, widthConstant: 25)
        view.tintColor = .text
        return view
    }()
    
    private let leadingLabel: UILabel = {
        let label = UILabel()
        label.textColor = .label
        label.text = "Start Date"
        label.numberOfLines = 0
        label.sizeToFit()
        return label
    }()
    
    let trailingLabel: UILabel = {
        let label = UILabel()
        label.text = "Friday, 17 July 2020"
        label.textColor = .label
        label.numberOfLines = 0
        label.textAlignment = .right
        return label
    }()
    
    let trailingImageView: UIImageView  = {
        let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
        let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
        let view = UIImageView(image: image)
        return view
    }()
    
    private let superStackView: UIStackView = {
        let view = UIStackView()
        view.distribution = .fillProportionally
        view.alignment = .center
        view.spacing = 16
        return view
    }()
    
    private  let containerView: UIView = {
        let view = UIView()
        view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        view.setContentHuggingPriority(.defaultHigh, for: .vertical)
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setUpSubviews()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}
extension TableViewCell {
    private  func setUpSubviews(){
        containerView.addSubview(trailingImageView)
        trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
                                      centerYAnchor: containerView.centerYAnchor)
        
        superStackView.addArrangedSubview(leadingImageView)
        superStackView.addArrangedSubview(leadingLabel)
        superStackView.addArrangedSubview(trailingLabel)
        superStackView.addArrangedSubview(containerView)
        
        let constant = CGFloat(16)
    
        self.addSubview(superStackView)
        self.contentView.addSubview(superStackView)
        superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
                              bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
                              topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
        
        
        self.contentView.updateConstraints()
        
    }
}

如何解决这个问题,使单元格看起来像下图中的单元格?

尝试Return 1

let trailingLabel: UILabel = {
        let label = UILabel()
        label.text = "Friday, 17 July 2020"
        label.textColor = .label
        label.numberOfLines = 1
        label.textAlignment = .right
        return label
    }()

你很接近...

首先,将堆栈视图的分布设置为 Fill Proportionally 是最容易被误解的分布选项,您不想在这里使用它。

其次,在设计时使用对比色背景非常有帮助,可以很容易地看到您的框架在做什么。

这是您的代码,经过修改以达到您的目标。我没有您的“约束助手”,所以我将其更改为标准约束格式。我还添加了一些评论以进行澄清:

class TableViewCell: UITableViewCell {
    
    static let identifier = "TableViewCell"
    
    private let leadingImageView: UIImageView = {
        let view = UIImageView(image: UIImage(systemName: "calendar"))
        view.translatesAutoresizingMaskIntoConstraints = false
        
        //view.setConstraints(heightConstant: 25, widthConstant: 25)
        view.widthAnchor.constraint(equalToConstant: 25).isActive = true
        view.heightAnchor.constraint(equalToConstant: 25).isActive = true

        view.tintColor = .blue // .text
        return view
    }()
    
    private let leadingLabel: UILabel = {
        let label = UILabel()
        label.textColor = .label
        label.text = "Start Date"
        // only single line for "leading label"
        label.numberOfLines = 1
        // content hugging
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.backgroundColor = .cyan
        return label
    }()
    
    let trailingLabel: UILabel = {
        let label = UILabel()
        label.text = "Friday, 17 July 2020"
        label.textColor = .label
        label.numberOfLines = 0
        label.textAlignment = .right
        label.backgroundColor = .green
        return label
    }()
    
    let trailingImageView: UIImageView  = {
        let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
        let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
        let view = UIImageView(image: image)
        return view
    }()
    
    private let superStackView: UIStackView = {
        let view = UIStackView()
        view.translatesAutoresizingMaskIntoConstraints = false
        // do NOT use .fillProportionally
        view.distribution = .fill
        view.alignment = .center
        view.spacing = 16
        return view
    }()
    
    private  let containerView: UIView = {
        let view = UIView()
        // not needed
        //view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        //view.setContentHuggingPriority(.defaultHigh, for: .vertical)
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setUpSubviews()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}
extension TableViewCell {
    private  func setUpSubviews(){
        containerView.addSubview(trailingImageView)
        //trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
        //                            centerYAnchor: containerView.centerYAnchor)
        
        superStackView.addArrangedSubview(leadingImageView)
        superStackView.addArrangedSubview(leadingLabel)
        superStackView.addArrangedSubview(trailingLabel)
        superStackView.addArrangedSubview(containerView)
        
        let constant = CGFloat(16)
        
        self.addSubview(superStackView)
        self.contentView.addSubview(superStackView)
        //superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
        //                            bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
        //                            topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
        
        NSLayoutConstraint.activate([
            
            trailingImageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
            trailingImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
            
            superStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: constant),
            superStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: constant),
            superStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -constant),
            superStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -constant),

        ])

        // not needed
        //self.contentView.updateConstraints()
        
    }
}

还有一个示例视图控制器:

class MahanTableViewController: UITableViewController {
    
    var myData: [String] = [
        "Saturday, 18 July 2020",
        "Sunday, 19 July 2020",
        "Wednesday, 22 July 2020",
        "Saturday, 26 September 2020",
        "Sunday, 27 September 2020",
        "Wednesday, 30 September 2020",
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
        
    }
    
    // MARK: - Table view data source
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell
        
        cell.trailingLabel.text = myData[indexPath.row]
        
        return cell
    }
    
}

生成此输出: