简体   繁体   English

如何以编程方式使集合视图单元格高度等于具有最高高度的文本

[英]How to make collection view cell height equal to the text with the highest height and programatically

I have a collection view which scrolls horizontally much like a carousel.我有一个像旋转木马一样水平滚动的集合视图。

The height and width of all the cells should be equal to the cell which has the longest text.所有单元格的高度和宽度应等于文本最长的单元格。

It doesn't do this however and instead expands it's width depending on the length of the text which results into different widths of cells though the height remains constant.然而,它并没有这样做,而是根据文本的长度扩展它的宽度,这会导致单元格的宽度不同,尽管高度保持不变。

max number of lines for the text is only 4.文本的最大行数仅为 4。

示例 gif

I tried other answers in SO but none of them worked for me.我在 SO 中尝试了其他答案,但没有一个对我有用。

Here is my code, I am using SnapKit for constraints.这是我的代码,我使用 SnapKit 进行约束。

View Controller查看 Controller

import UIKit
import SnapKit

class ViewController: UIViewController {
    
    
    let viewModel: [SeatViewModel] = [.init(text: "single text"), .init(text: "slightly longer text."), .init(text: "very very very very long long text")]
    
    var collectionViewSize: CGFloat = 10
    
    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.estimatedItemSize = CGSize(width: 200, height: 100)
        let cv = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        cv.register(SeatCardCell.self, forCellWithReuseIdentifier: "SeatCardCell")
        return cv
    }()
    


    override func viewDidLoad() {
        super.viewDidLoad()
                
        self.view.addSubview(collectionView)
        
        collectionView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.leading.equalToSuperview()
            make.trailing.equalToSuperview()
            make.height.equalTo(100)
        }
        collectionView.dataSource = self
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.frame = view.bounds
    }
    
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let collectioCell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatCardCell", for: indexPath) as? SeatCardCell else { fatalError() }
        collectioCell.backgroundColor = [UIColor.green, .red, .black, .brown, .yellow].randomElement()
        collectioCell.viewModel = viewModel[indexPath.row]
        return collectioCell
    }
}

Cell and View Model单元格和视图 Model

struct SeatViewModel {
    let text: String
}

class SeatCardCell: UICollectionViewCell {
    
    var viewModel: SeatViewModel? {
        didSet {
            configure()
        }
    }

    // MARK: - Properties

    let seatImageView = UIImageView(image: nil)
    
    let seatLabel: CustomLabel = {
        let label = CustomLabel()
        return label
    }()

    // MARK: - Lifecycle

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

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

    
    private func configure() {
        guard let viewModel = viewModel else { return }
        seatLabel.text = viewModel.text
        seatLabel.backgroundColor = .cyan
        seatLabel.sizeToFit()
        seatImageView.image = .strokedCheckmark
        
        let stackView = UIStackView(arrangedSubviews: [seatImageView, seatLabel])
        stackView.spacing = 0
        stackView.alignment = .center
        
        addSubview(stackView)
        
        seatImageView.snp.makeConstraints { make in
            make.size.equalTo(40)
        }
        
        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
}


// MARK: - CUSTOM TITLE LABEL
class CustomLabel: UILabel {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupUI() {
        self.textColor = .darkGray
        self.textAlignment = .left
        self.numberOfLines = 4
    }
}

Assuming you want all of the cells to be the same size...假设您希望所有单元格的大小相同......

One possible solution would be to use NSString.boundingRect .一种可能的解决方案是使用NSString.boundingRect In a place where you only need to calculate this once, for example in viewDidLoad, determine the bounding rect of the largest text:在只需要计算一次的地方,例如在viewDidLoad,确定最大文本的边界矩形:

var maxTextWidth: CGFloat = 0

override func viewDidLoad() {
    // All the other code you currently have, plus:

    let boundingWidth = 9999 // Something arbitrarily large
    let boundingHeight = 34 // Make this the height of however many lines you want
    let targetSize = CGSize(width: boundingWidth, height: boundingHeight)
    let attributes = [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 17)] // Put any other necessary attributes to accurately calculate the size of the text
    
    for vm in viewModel {
        let width = NSString(string: vm.text).boundingRect(with: estimatedSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).width
        if width > maxTextWidth {
            maxTextWidthWidth = width
        }
    }
}

And then you also need to provide this size to the collection view using:然后您还需要使用以下方法将这个大小提供给集合视图:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = maxTextWidth + // Any padding you want
    let height = // Height of text plus any padding
    return CGSize(width: width, height: height)
}

More documentation on boundingRect can be found here可以在此处找到有关boundingRect的更多文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何以编程方式为iOS中的集合视图单元格提供宽度和高度,Swift 3 - How to give width and height programatically for collection view cell in ios, swift 3 自动收集视图单元格高度 - Auto collection view cell Height 如何在自定义单元格中使UIImage的宽度等于视图的宽度和比例高度 - How to make UIImage width be equal to view's width and proportional height inside a custom cell 如何使用情节提要中定义的单元格来计算集合视图单元格的高度? - How to calculate collection view cell height using cell defined in storyboard? 如何使用一系列视图中具有最高高度的视图进行约束 - How to make a constraint use the view with highest height from an array of views 如何以编程方式调整相等高度的AutoLayout乘数? - How to adjust equal height AutoLayout multiplier programatically? 标签文本增加时,如何以编程方式增加集合视图单元格的高度? - How to programmatically increase collection view cell height when label text increases? 如何使UIScrollView的高度等于内容的高度? - How to make UIScrollView height equal to content height? 如何在Swift iOS中调整集合视图单元格的高度? - How to adjust collection view cell height in swift ios? 设置集合视图单元格的动态宽度和高度 - set Dynamic width and height of collection view cell
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM