iOS - Как установить якоря, чтобы настроить интервал для разрыва строки с помощью саморазмера ячеек CollectionView - PullRequest
0 голосов
/ 10 ноября 2018

При настройке текста метки для самостоятельного захвата ячеек 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
}

Функция работает нормально, и мои клетки соответственно расширяются.

Что произошло, так это то, что в тексте есть несколько разрывов строк из ценовой метки, которые вводятся в функцию. Разрывы строк слишком "плотные", поэтому я следовал этому ответу при создании метки , чтобы увеличить интервал между разрывами строк.

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))

Проблема в том, что текст из ценовой метки внутри ячейки расширяется вниз. Использование paragraphStyle.lineSpacing = 7 создает пространство, которое я хочу, но вызывает проблемы. Если я установлю это на paragraphStyle.lineSpacing = 2, то проблем не будет, но интервал слишком узкий.

enter image description here

Как вы можете видеть на рисунке, размеры ячеек должны быть такими, какими они должны быть, но из-за разрыва строки между $ 8,00 и $ 12,00 текст расширяется до предела, а текст $ 20,00 из computedTotalLabel затеняется.

Я позвонил sizeToFit() в layoutSubViews(), но без разницы:

override func layoutSubviews() {
    super.layoutSubviews()

    pricesLabel.sizeToFit()
    computedTotalLabel.sizeToFit()
}

Как сделать так, чтобы текст valuesLabel корректировался с учетом размера разрывов строк

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
    }
}

Это sizeForItem внутри ячейки collectionView. Не уверен, что это изменит проблему, поэтому я все равно добавил ее

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 голосов
/ 10 ноября 2018

первый. Я должен был поместить тот же estimatedLabelHeight(text: String, width: CGFloat, font: UIFont) внутри самой ячейки collectionView.

второй. Внутри функций configureAnchors в нижней части я вызываю pricesLabel.sizeToFit() и pricesLabel.layoutSubviews(), а затем вызываю вышеуказанную функцию с шага 1, чтобы получить высоту ценовой метки из ее текста.

третий. Я установил 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
    }
}
...