【问题标题】:AutoLayout: multiline label and fixed-size buttonAutoLayout:多行标签和固定大小的按钮
【发布时间】:2018-10-17 13:37:33
【问题描述】:

我正在尝试从 Kayak 应用复制以下布局:

布局由 UICollectionViewCell 和一个 UILabel 和一个 INUIAddVoiceShortcutButton 组成。

但是,在我的实现中,当文本不适合时,标签不会强制单元格进一步拉伸:

我怎样才能使 UICollectionViewCell 随标签一起增长,而不是将标签截断为单元格的大小?

单元格的完整代码:

final class AddToSiriCell: CornerMaskCellBase {
  lazy var button: INUIAddVoiceShortcutButton = {
    let b = INUIAddVoiceShortcutButton(style: .whiteOutline)
    return b
  }()

  lazy var textLabel: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    return label
  }()

  override init(frame: CGRect) {
    super.init(frame: frame)
    configureViews()
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  private func configureViews() {
    textLabel.text = "View balance with your pre-recorded Siri Command .View balance with your pre-recorded Siri Command  View balance with your pre-recorded Siri Command View balance with your pre-recorded Siri Command "
    contentView.backgroundColor = .white
    [button, textLabel].forEach(contentView.addSubview)
    button.snp.makeConstraints { (make) in
      make.top.bottom.trailing.equalTo(contentView.layoutMarginsGuide)
    }

    textLabel.snp.makeConstraints { (make) in
      make.top.bottom.leading.equalTo(contentView.layoutMarginsGuide).priority(.required)
      make.trailing.equalTo(button.snp.leading).priority(.required)
    }
  }
}

更新 1:添加了固定宽度的“基类” 这是我用于 UICollectionView 中所有单元格的基类:

import UIKit
import SnapKit

class AutoSizingCellBase: UICollectionViewCell {
  override class var requiresConstraintBasedLayout: Bool {
    return true
  }

  private final var widthConstraint: Constraint?

  override init(frame: CGRect) {
    super.init(frame: frame)
    contentView.layoutMargins = UIEdgeInsets(padding: 14)
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func updateConstraints() {
    if widthConstraint == nil {
      if let window = window {
        let width = window.bounds.width - 16
        contentView.snp.makeConstraints { (make) in
          widthConstraint = make.width.equalTo(width).priority(.required).constraint
        }
      }
      contentView.translatesAutoresizingMaskIntoConstraints = true
    }
    super.updateConstraints()
  }
}

【问题讨论】:

    标签: ios autolayout uikit uilabel snapkit


    【解决方案1】:

    将标签和按钮的顶部约束设置为greaterThanOrEqual

    将标签和按钮的底部约束设置为lessThanOrEqual


    编辑:

    两者都应该有centerY 约束。

    这是一个完整的示例(我不在 iOS 12 上,所以我使用标准的 UIButton 代替 INUIAddVoiceShortcutButton)。我还将标签的背景设置为青色,以便于查看其生成的帧:

    //
    //  SnapTableViewController.swift
    //
    //  Created by Don Mag on 10/19/18.
    //
    
    import UIKit
    
    class SnapCell: UITableViewCell {
    
        lazy var theButton: UIButton = {
            let b = UIButton()
            b.backgroundColor = .yellow
            b.setTitle("Add to Siri", for: .normal)
            b.setTitleColor(.black, for: .normal)
            b.layer.cornerRadius = 8
            b.layer.borderColor = UIColor.black.cgColor
            b.layer.borderWidth = 1
            return b
        }()
    
        lazy var theLabel: UILabel = {
            let label = UILabel()
            label.numberOfLines = 0
            label.backgroundColor = .cyan
            return label
        }()
    
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            configureViews()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            configureViews()
        }
    
        func configureViews() -> Void {
    
            contentView.backgroundColor = .white
            [theButton, theLabel].forEach(contentView.addSubview)
    
            // constrain button size to 120 x 40
            theButton.snp.makeConstraints { (make) in
                make.width.equalTo(120)
                make.height.equalTo(40)
            }
    
            // constrain button to trailing margin
            theButton.snp.makeConstraints { (make) in
                make.trailing.equalTo(contentView.layoutMarginsGuide)
            }
    
            // constrain button top to greaterThanOrEqualTo margin
            theButton.snp.makeConstraints { (make) in
                make.top.greaterThanOrEqualTo(contentView.layoutMarginsGuide)
            }
    
            // constrain button bottom to lessThanOrEqualTo margin
            theButton.snp.makeConstraints { (make) in
                make.bottom.lessThanOrEqualTo(contentView.layoutMarginsGuide)
            }
    
            // also constrain button to centerY
            theButton.snp.makeConstraints { (make) in
                make.centerY.equalTo(contentView.snp.centerY)
            }
    
            // constrain label to leading margin
            theLabel.snp.makeConstraints { (make) in
                make.leading.equalTo(contentView.layoutMarginsGuide)
            }
    
            // constrain label top to greaterThanOrEqualTo margin
            theLabel.snp.makeConstraints { (make) in
                make.top.greaterThanOrEqualTo(contentView.layoutMarginsGuide)
            }
    
            // constrain label bottom to lessThanOrEqualTo margin
            theLabel.snp.makeConstraints { (make) in
                make.bottom.lessThanOrEqualTo(contentView.layoutMarginsGuide)
            }
    
            // also constrain label to centerY
            theLabel.snp.makeConstraints { (make) in
                make.centerY.equalTo(contentView.snp.centerY)
            }
    
            // constrain label trailing to 8-pts from button leading
            theLabel.snp.makeConstraints { (make) in
                make.trailing.equalTo(theButton.snp.leading).offset(-8)
            }
    
        }
    
    }
    
    class SnapTableViewController: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.rowHeight = UITableViewAutomaticDimension
            tableView.estimatedRowHeight = 100
    
        }
    
        // MARK: - Table view data source
        override func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 10
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SnapCell", for: indexPath) as! SnapCell
    
            switch indexPath.row % 4 {
    
            case 0:
                cell.theLabel.text = "One line label."
    
            case 1:
                cell.theLabel.text = "This label has\nTwo Lines."
    
            case 2:
                cell.theLabel.text = "This label has enough text that is will wrap to Three Lines (on an iPhone 7)."
    
            default:
                cell.theLabel.text = "View balance with your pre-recorded Siri Command .View balance with your pre-recorded Siri Command  View balance with your pre-recorded Siri Command View balance with your pre-recorded Siri Command "
    
            }
    
            return cell
        }
    
    }
    

    【讨论】:

    • 我已经用代码示例和屏幕截图更新了我的答案
    • @RichardTopchiy - 查看我编辑的答案以获取完整示例。
    • 您展示的演示项目看起来很棒!这正是我想要的行为。不过,我用的是 UICollectionView,我也来看看它的表现如何……
    • 您的示例运行良好,非常感谢!不幸的是,问题似乎出在我的应用中处理大小的方式上。
    • 有趣的是,我运行了您的示例,然后使用 UICollectionView 重新创建了相同的单元格并得到了完全不同的结果(启用了自动调整大小的单元格):user-images.githubusercontent.com/8013017/…
    【解决方案2】:

    使用超级视图(即单元格的内容视图)设置标签的顶部、底部和左侧约束。现在将您的按钮设置为固定的高度和宽度限制,并提供顶部、左侧和右侧边距,左边距应该与您的标签一起使用。现在将标签的行数属性设置为零。有任何疑问欢迎评论。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多