简体   繁体   English

如何在具有无限行的UILabel上自动换行?

[英]How to word wrap on UILabel that has infinite lines?

I have a UILabel in which the number of lines need to be set to 0 (infinite lines). 我有一个UILabel,其中行数需要设置为0(无限行)。 But when it displays a single long word, it breaks the line by character, to form a second line. 但是,当它显示单个长字时,它会按字符将行换行,以形成第二行。 I tried to set Line breaking mode manually as such 我试图手动设置换行模式

cell.nameLbl.adjustsFontSizeToFitWidth = true
cell.nameLbl.lineBreakMode = .byWordWrapping

But the app still breaks by character. 但是该应用仍会因字符而中断。 How can I fix this? 我怎样才能解决这个问题? Edit- I want the word font size to shrink. 编辑-我想缩小字型大小。

Adjusting font size is unfortunately done per label, not per line. 不幸的是,调整字体大小是按标签而不是按行完成的。 Wrapping does not effect it. 包装不会影响它。 So the result you are seeing is expected. 因此,您所看到的结果是预期的。 You could split your string manually into multiple labels maybe putting them into stack view to get desired result. 您可以将字符串手动拆分为多个标签,也可以将它们放入堆栈视图中以获得所需的结果。

What I tried was: 我试过的是:

private func layoutText(text: String, onStackView stackView: UIStackView) {
    var words: [String] = text.components(separatedBy: .whitespaces)

    var currentLineWords: [String] = [String]()
    var currentLabel: UILabel!

    func newLabel() -> UILabel {
        let label = UILabel(frame: stackView.bounds)
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        return label
    }

    while words.count > 0 {
        if currentLineWords.count == 0 {
            currentLabel = newLabel()
            currentLineWords.append(words.removeFirst())
        } else {
            let newText = currentLineWords.joined(separator: " ") + " " + words[0]
            currentLabel.text = newText
            currentLabel.sizeToFit()

            if currentLabel.bounds.width > stackView.bounds.width {
                // Break line
                currentLabel.text = currentLineWords.joined(separator: " ")
                stackView.addArrangedSubview(currentLabel)
                currentLabel = nil
                currentLineWords = [String]()
            } else {
                // All good
                currentLineWords.append(words.removeFirst())
            }
        }
    }

    if currentLineWords.count > 0 {
        currentLabel.text = currentLineWords.joined(separator: " ")
        stackView.addArrangedSubview(currentLabel)
    }
}

This works pretty neatly but: 这工作得很整洁,但是:

  • When word is too long to fit in a line even when shrunk it will show "..." at the end 当单词太长而不能缩成一行时,它的末尾将显示“ ...”
  • Shrunk line still has the same height instead of having it reduced 收缩线仍然具有相同的高度,而不是减小高度
  • We are only handling whitespaces and inserting back spaces 我们只处理空白并插入退格

The first 2 would probably both be solved by having manual adjustsFontSizeToFitWidth . 前两个可能都可以通过手动adjustsFontSizeToFitWidth来解决。 Basically keep reducing font size until it fits or until a certain size. 基本上一直减小字体大小,直到适合为止或达到一定大小为止。 If "certain size" scenario is hit then simply use multiline on a label (will break by characters). 如果遇到“一定大小”的情况,则只需在标签上使用多行(将按字符分隔)。

The last one just need some extra effort. 最后一个只需要付出额外的努力。

I would still not implement this for multiple reasons one of them being that it looks ugly but is still interesting. 由于种种原因,我仍然不会执行此操作,其中一个原因是它看上去很丑,但仍然很有趣。

Custom font size adjustment: 自定义字体大小调整:

To have custom font adjustment and all the logic there is only a change when a new lien is created: 要进行自定义字体调整和所有逻辑,只有在创建新的留置权后才需要更改:

            if currentLineWords.count == 0 {
                currentLabel = newLabel()
                currentLineWords.append(words.removeFirst())

                currentLabel.text = currentLineWords.joined(separator: " ")
                currentLabel.sizeToFit()

                if currentLabel.bounds.width > stackView.bounds.width {
                    currentLabel.adjustsFontSizeToFitWidth = false

                    let originalFontSize: CGFloat = currentLabel.font.pointSize
                    var currentFontSize: CGFloat = originalFontSize
                    let minimalFontSize: CGFloat = currentLabel.minimumScaleFactor > 0.0 ? currentLabel.font.pointSize * currentLabel.minimumScaleFactor : originalFontSize

                    while currentLabel.bounds.width > stackView.bounds.width {
                        currentFontSize -= 1.0
                        if currentFontSize < minimalFontSize {
                            currentLabel.numberOfLines = 0
                            currentLabel.font = UIFont(name: currentLabel.font.fontName, size: originalFontSize)
                            break // Could not shrink it even further. USe multiline
                        }
                        currentLabel.font = UIFont(name: currentLabel.font.fontName, size: currentFontSize)
                        currentLabel.sizeToFit()
                    }

                    // Break line
                    stackView.addArrangedSubview(currentLabel)
                    currentLabel = nil
                    currentLineWords = [String]()
                }
            } 

This looks usable now. 现在看起来可用。 My result: 我的结果:

在此处输入图片说明

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM