首页 文章

在水平滚动中设置具有不同宽度的单元格的collectionView的大小

提问于
浏览
0

我正在尝试将UICollectionView设置为水平菜单,在另一个UICollectionView之上(但这是无关紧要的) .

现在我的细胞基本上由标签组成,你可以想象不同的宽度 . 所以我尝试用这个函数计算大小:

func getSizeOfCell(string: String, font: UIFont) -> CGSize {
    let textString = string as NSString
    let textAttributes = [NSFontAttributeName: font]
    let size = textString.boundingRect(with: CGSize(width: 320, height: 2000), options: .usesLineFragmentOrigin, attributes: textAttributes, context: nil)
    return CGSize(width: size.width, height: size.height)
}

你可以看到哪个不是真的做得很好:
enter image description here

当字符串很长时,包含标签的视图太大 .

我有点被迫给sizeForItem一个CGSize吧?我不能只是让我的CollectionView根据它包含的标签自动获取单元格的大小?

[编辑]所以这是我的细胞类:

class MenuCell: UICollectionViewCell {
override init(frame: CGRect) {
    super.init(frame: frame)

    setupViews()
}

override var isSelected: Bool {
    didSet {
        labelTitre.textColor = isSelected ? UIColor.black : .lightGray
    }
}

let labelTitre : UILabel = {
    let label = UILabel()
    label.textColor = .gray
    return label
}()

func setupViews() {
    backgroundColor = UIColor.white
    addSubview(labelTitre)
    addConstraintsWithFormat(format: "H:[v0]", views: labelTitre)
    addConstraintsWithFormat(format: "V:[v0]", views: labelTitre)
    addConstraint(NSLayoutConstraint(item: labelTitre, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
    addConstraint(NSLayoutConstraint(item: labelTitre, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))

}



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

这是我构建我的collectionView的方法:

lazy var customCollectionView : UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    layout.minimumLineSpacing = 0
    layout.minimumInteritemSpacing = 0
    layout.estimatedItemSize = CGSize(width: 60, height: 30)
    let cv  = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.collectionViewLayout = layout
    cv.backgroundColor = UIColor.white
    cv.dataSource = self
    cv.delegate = self
    return cv

}()

同样在我的viewController的viewDidLoad()中:

customCollectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
    addSubview(customCollectionView)
    addConstraintsWithFormat(format: "V:|[v0]|", views: customCollectionView)
    addConstraintsWithFormat(format: "H:|[v0]|", views: customCollectionView)

1 回答

  • 3

    您可以使用约束来使单元格“自动调整大小”,并且您不必手动计算文本/标签大小 .

    试一试 . 当然,它需要修改以满足您的需求,但应该给您一些工作( Edit :我更新了我的代码以更接近您的方法):

    //
    //  MenuBarViewController.swift
    //
    
    import UIKit
    
    private let reuseIdentifier = "MyASCell"
    
    class MyMenuCell: UICollectionViewCell {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            setupViews()
        }
    
        override var isSelected: Bool {
            didSet {
                labelTitre.textColor = isSelected ? UIColor.black : .lightGray
            }
        }
    
        let labelTitre : UILabel = {
            let label = UILabel()
            label.textColor = .gray
            return label
        }()
    
        func setupViews() {
            backgroundColor = UIColor.white
            addSubview(labelTitre)
    
            labelTitre.translatesAutoresizingMaskIntoConstraints = false
    
            // set constraints to use the label's intrinsic size for auto-sizing
            // we'll use 10 pts for left and right padding
            labelTitre.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10.0).isActive = true
            labelTitre.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10.0).isActive = true
    
            // center the label vertically (padding controlled by collectionView's layout estimated size
            labelTitre.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    }
    
    class MyMenuBarViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
        var theLabels = [
            "Intro",
            "Aborigenes",
            "Faune",
            "Flore",
            "Randonnées",
            "A longer label here",
            "End"
        ]
    
        lazy var theCollectionView : UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
            layout.minimumLineSpacing = 1.0
            layout.minimumInteritemSpacing = 1.0
            // note: since the labels are "auto-width-stretching", the height here defines the actual height of the cells
            layout.estimatedItemSize = CGSize(width: 60, height: 28)
            let cv  = UICollectionView(frame: .zero, collectionViewLayout: layout)
            // using lightGray for the background "fills in" the spacing, giving us "cell borders"
            cv.backgroundColor = UIColor.lightGray
            cv.dataSource = self
            cv.delegate = self
            return cv
    
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.view.backgroundColor = .yellow
    
            // register the cell
            //      theCollectionView.register(MyASCell.self, forCellWithReuseIdentifier: reuseIdentifier)
            theCollectionView.register(MyMenuCell.self, forCellWithReuseIdentifier: reuseIdentifier)
    
            // we're going to add constraints, so don't use AutoresizingMask
            theCollectionView.translatesAutoresizingMaskIntoConstraints = false
    
            // add the "menu bar" to the view
            self.view.addSubview(theCollectionView)
    
            // pin collection view to left and right edges
            theCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            theCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    
            // pin top of collection view to topLayoutGuide
            theCollectionView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
    
            // set height of collection view to 30
            theCollectionView.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
    
    
            // for demonstration's sake, just add a blue view below the "menu bar"
            let v = UIView(frame: CGRect.zero)
            v.backgroundColor = UIColor.blue
            v.translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(v)
    
            // pin gray view to left, right, bottom of view
            v.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
            v.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
            v.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
    
            // pin top of gray view to bottom of collection view
            v.topAnchor.constraint(equalTo: theCollectionView.bottomAnchor).isActive = true
    
        }
    
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
            // we want a 1-pt border on top, bottom and left and right edges of the collection view itself
            return UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
        }
    
        func numberOfSections(in collectionView: UICollectionView) -> Int {
            return 1
        }
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return theLabels.count
        }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyMenuCell
    
            cell.labelTitre.text = theLabels[indexPath.row]
    
            // just simulating selection here...
            cell.isSelected = indexPath.row == 0
    
            return cell
        }
    
    }
    

    Edit:

    以下是我的代码结果的上限:

    enter image description here

    并且代码的结果上限 - 编辑了一行:

    enter image description here

    在您的单元格代码中,更改:

    addConstraintsWithFormat(format: "H:[v0]", views: labelTitre)
    

    至:

    addConstraintsWithFormat(format: "H:|-10-[v0]-10-|", views: labelTitre)
    

相关问题