1

i create a tab menu using collectionViewCell but, i have 5 cell menu. but the name in cell got truncate, i want if there is a long name label. the container view in collectionViewCell should grow.

truncate label

i try to use the collectionViewFlowLayout estimatedItemSize, but the result is. the cell become ugly not like before

estimatedItemSize

How to make the collectionViewCell grow size but maintain full width.

this is my setup for my collectionViewCell

private let padding: CGFloat = 8

override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    
required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
}

private func configure() {
        addSubview(selectionView)
        selectionView.addSubview(titleLabel)

        NSLayoutConstraint.activate([
            selectionView.topAnchor.constraint(equalTo: topAnchor, constant: padding),
            selectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4),
            selectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -4),
            selectionView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -padding),

            titleLabel.topAnchor.constraint(equalTo: selectionView.topAnchor, constant: padding),
            titleLabel.leadingAnchor.constraint(equalTo: selectionView.leadingAnchor, constant: 4),
            titleLabel.trailingAnchor.constraint(equalTo: selectionView.trailingAnchor, constant: -4),
            titleLabel.bottomAnchor.constraint(equalTo: selectionView.bottomAnchor, constant: -padding)
        ])
    }

and this is my setup for my collectionView

private func setupCollectionView() {
        let layout = UICollectionViewFlowLayout()
        layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

        collectionView = UICollectionView(frame: bounds, collectionViewLayout: layout)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(TabCollectionViewCell.self, forCellWithReuseIdentifier: TabCollectionViewCell.cellID)

        [notificationLabel, collectionView].forEach { view in
            guard let view = view else { return }
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubview(view)
        }

        NSLayoutConstraint.activate([
            notificationLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8),
            notificationLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
            notificationLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),

            collectionView.topAnchor.constraint(equalTo: notificationLabel.bottomAnchor, constant: 8),
            collectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
            collectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),
            collectionView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
        ])

    }

extension HeaderCollectionView: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width / CGFloat(items.count), height: collectionView.bounds.height)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

}
4
  • So, you want a certain minimum width, but for cells that need to be larger, you want it to grow with the text? Try adding a selectionView.widthAnchor.constraint(greaterThanOrEqualToConstant: minWidth). Commented Nov 19, 2022 at 6:28
  • yes that's right @Rob i want the cell grow by the text. I try your method but still not working. it still like the second one, Commented Nov 19, 2022 at 6:42
  • 2
    Seems like it would be a lot simpler to put the 5 buttons in a UIStackView instead of using a UICollectionView. Commented Nov 19, 2022 at 7:21
  • ferryawaijayanto - Yes, my widthAnchor technique (with .automaticSize, but no sizeForItemAt) will achieve the second the second. I didn’t know what you meant by “grow but maintain will width”. I now understand what you’re trying to achieve. And HangarRash is 100% right, that a stack view is the right solution, rather than contorting yourself with collection view. You should only use collection view if you need scrolling behavior. Commented Nov 20, 2022 at 20:01

1 Answer 1

1

Create a String extension method that will calculate the width of the string and after that use that in your delegate method:

Step 1: Calculate the string width

extension String {
    func getStringwidth(height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
        return boundingBox.width
    }
}

Step 3: Calculate the max width

func calculateMaxWidth()-> CGFloat {
        // my Data shource array Data
        var allSize: [CGFloat] = []
        arrayData.forEach{
            allSize.append($0.widthWithConstrainedHeight(height: 30,
                                                         font: UIFont.systemFont(ofSize: 17)))
        }
        return allSize.max() ?? 0.0
        
    }

Step 2: Call the max from viewdidLoad

    override func viewDidLoad() {
    super.viewDidLoad()
    
    let layout = UICollectionViewFlowLayout()
    layout.estimatedItemSize =  CGSize(width: calculateMaxWidth(), height: 30)

Adjust based on your requirement.

Output: enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

thank you for your help, i try your method. it's still not working, i think it makes easier if use stackView like @HangarRash said
@ferryawijayanto That is another solution. I update my answer and try that. It is working for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.