0

I need to create a collection of tags within a UITableViewCell.

These tags are clickable so I have decided to render them using UIButton and I will style to suit.

I thought I could create a cell containing a UIStackView and add in the buttons, which should wrap if they do not fit.

However the stackview seems to be stuck on a single line and the buttons are squash and un readable.

I thought I could set the width of the button based on the text width but this does not appear to work either.

enter image description here

final class ProfileFollowedTopics: UITableViewCell {
  var topics: [String] = ["Topic #01", "Topic #02", "Topic #03", "Topic #04", "Topic #05", "Topic #06", "Topic #07", "Engineering", "Code", "Whiskey"]

  override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    configureUI()
  }

  required init?(coder: NSCoder) {
    return nil
  }

}

private extension ProfileFollowedTopics {
  func configureUI() {

    let stackView = UIStackView(frame: .zero)
    stackView.translatesAutoresizingMaskIntoConstraints = false

    contentView.addSubview(stackView)

    NSLayoutConstraint.activate([
      stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
      stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
      stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
      stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
    ])

    topics.forEach { topic in
      let textWidth = topic.widthOfString(usingFont: .systemFont(ofSize: 14))
      let button = UIButton(type: .system)
      button.setTitle(topic, for: .normal)
      button.setTitleColor(.black, for: .normal)
      button.titleLabel?.font = .systemFont(ofSize: 14)
      button.widthAnchor.constraint(equalToConstant: textWidth).isActive = true
      stackView.addArrangedSubview(button)
    }

    stackView.addArrangedSubview(UIView())
  }
}

extension String {
  func widthOfString(usingFont font: UIFont) -> CGFloat {
    let fontAttributes = [NSAttributedString.Key.font: font]
    let size = self.size(withAttributes: fontAttributes)
    return size.width
  }
}

Is it possible to achieve this without resorting to 3rd party libraries?

I'd like the items to left align in the stackview and wrap to a new line if they do not fit on a single row.

Harry Blue
  • 4,202
  • 10
  • 39
  • 78

0 Answers0