iOS-如何使用自动调整大小的CollectionView单元格设置锚点以调整换行的间距

时间:2018-11-10 02:49:01

标签: ios swift uicollectionview uilabel uicollectionviewcell

在调整标签文本以自动捕获collectionView单元格时,我在sizeForItem中使用以下功能:

func estimatedLabelHeight(text: String, width: CGFloat, font: UIFont) -> CGFloat {
    let size = CGSize(width: width, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let attributes = [NSAttributedStringKey.font: font]
    let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height
    return rectangleHeight
}

该功能正常运行,并且我的单元格相应扩展。

尽管发生了什么,但是pricesLabel的某些文本中有多个换行符,这些换行符被馈送到函数中。换行符太“紧”,所以我跟随this answer when creating my label扩大了换行符之间的间隔。

let attributedString = NSMutableAttributedString(string: pricesText)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 7 // if I set this at 2 I have no problems
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length))

问题是单元格中来自pricesLabel的文本向下扩展到了很远。使用paragraphStyle.lineSpacing = 7会创建我想要的空间,但会引起问题。如果我将其设置为paragraphStyle.lineSpacing = 2没问题,但是间距要紧。

enter image description here

您可以在图片中看到单元格的大小,但换行符介于$ 8.00和$ 12.00之间,使文本扩展到很远,而computeTotalLabel中的$ 20.00文本变得模糊了。

我在sizeToFit()中叫layoutSubViews(),但没什么区别:

override func layoutSubviews() {
    super.layoutSubviews()

    pricesLabel.sizeToFit()
    computedTotalLabel.sizeToFit()
}

如何根据行间断本身的大小调整pricesLabel文本

class MyCell: UICollectionViewCell {

    let pricesLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textAlignment = .right
        label.sizeToFit()
        label.font = UIFont.systemFont(ofSize: 15.5)
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        label.numberOfLines = 0
        label.sizeToFit()
        return label
    }()

    let computedTotalLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textAlignment = .right
        label.textColor = .black
        label.sizeToFit()
        label.font = UIFont.boldSystemFont(ofSize: 15.5)
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        label.numberOfLines = 1
        label.sizeToFit()
        return label
    }()

    let staticTotalLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Total"
        label.textAlignment = .left
        label.textColor = .black
        label.font = UIFont.boldSystemFont(ofSize: 15.5)
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        label.numberOfLines = 1
        label.sizeToFit()
        return label
    }()

    let separatorLine: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .lightGray
        return view
    }()

    override func layoutSubviews() {
        super.layoutSubviews()

        pricesLabel.sizeToFit()
        computedTotalLabel.sizeToFit()
    }

    var myObject: MyObject? {
        didSet {

           // text is "$8.00\n$12.00\n"
           let pricesText = myObject?.myText ?? "error"

           let attributedString = NSMutableAttributedString(string: pricesText, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 15.5)])
           let paragraphStyle = NSMutableParagraphStyle()
           paragraphStyle.lineSpacing = 7
           attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length))

           pricesLabel.attributedText = attributedString

           computedTotalLabel.text = functionThatTalliesUpAllThePrices(pricesText)

           configureAnchors()
        }
    }

    func configureAnchors() {

        addSubview(pricesLabel)
        addSubview(totalLabel)
        addSubview(staticTotalLabel) // this is the label on the left side of the pic that says Total:
        addSubview(separatorLine)

        pricesLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 12).isActive = true
        pricesLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true

        staticTotalLabel.lastBaselineAnchor.constraint(equalTo: totalLabel.lastBaselineAnchor).isActive = true
        staticTotalLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
        staticTotalLabel.rightAnchor.constraint(equalTo: totalLabel.leftAnchor, constant: -10).isActive = true

        computedTotalLabel.topAnchor.constraint(equalTo: pricesLabel.bottomAnchor, constant: 0).isActive = true
        computedTotalLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true

        separatorLine.topAnchor.constraint(equalTo: computedTotalLabel.bottomAnchor, constant: 12).isActive = true
        separatorLine.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
        separatorLine.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true
        separatorLine.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        separatorLine.heightAnchor.constraint(equalToConstant: 1).isActive = true
    }
}

这是collectionView单元内的sizeForItem。不知道这是否可以解决问题,所以我还是添加了它

class MyClass: UIViewController {

    let tableData = [MyObect]()

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let myObect = tableData[indexPath.item]

        // text is "$8.00\n$12.00\n"
        let pricesText = myObject?.myText ?? "error"

        let width = collectionView.frame.width

        let pricesLabelHeight = estimatedLabelHeight(text: pricesText, width: width, font: UIFont.systemFont(ofSize: 15.5))

        let total = functionThatTalliesUpAllThePrices(pricesText)
        let totalLabelHeight = estimatedLabelHeight(text: functionThatAddsUp, width: width, font: UIFont.boldSystemFont(ofSize: 15.5))

        // the 12 + 0 + 12 + 1 are the constant sizes I use inside the cell's configureAnchors functions
        let cellHeight = 12 + pricesLabelHeight + 0 + totalLabelHeight + 12 + 1

        return CGSize(width: width, height: ceil(cellHeight))
    }
}

1 个答案:

答案 0 :(得分:0)

1st。我必须将相同的estimatedLabelHeight(text: String, width: CGFloat, font: UIFont)放在collectionView单元格本身中。

第二。在其底部的configureAnchors函数内部,我分别调用pricesLabel.sizeToFit()pricesLabel.layoutSubviews(),然后从步骤1中调用上述函数,以从其文本中获取pricesLabel的高度。

3rd。我将pricesLabel.heightAnchor.constraint(equalToConstant:)设置为步骤2返回的高度。

class MyCell: UICollectionViewCell {

    // step 1. place this function inside the collectionView cell
    func estimatedLabelHeight(text: String, width: CGFloat, font: UIFont) -> CGFloat {

        let size = CGSize(width: width, height: 1000)

        let options = NSStringDrawingOptions.usesFontLeading.union([.usesLineFragmentOrigin, .usesFontLeading])

        let attributes = [NSAttributedStringKey.font: font]

        let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height

        return rectangleHeight
    }

    func configureAnchors() {

        // all the other anchors are here

        pricesLabel.sizeToFit()
        computedTotalLabel.sizeToFit()

        computedTotalLabel.layoutIfNeeded()
        pricesLabel.layoutIfNeeded()

        let pricesLabelText = pricesLabel.text ?? "error"

        let width = self.frame.width

        // step 2.
        let pricesLabelHeight = estimatedLabelHeight(text: pricesLabelText, width: width, font: UIFont.systemFont(ofSize: 15.5))

        // step 3.
        pricesLabel.heightAnchor.constraint(equalToConstant: pricesLabelHeight).isActive = true
    }
}