【问题标题】:UILabel word wrap feature leaving space even when sufficient space available for the word即使有足够的空间可用于单词,UILabel 自动换行功能也会留下空间
【发布时间】:2021-04-11 04:07:34
【问题描述】:

这个问题甚至出现在故事​​板中。

UILabel 具有以下属性:

  • numberOfLines = 0
  • lineBreakMode = .byWordWrapping
  • 约束:领先和落后 26 点到 superview;垂直居中。
  • 自定义字体:中等 17 磅。

如您所见,第四个单词无法放入第一行,因此会出现布局错误的问题。如果我删除最后一个单词,则句子完全适合一行或说出第四个单词。如果在它之后添加一个单词会将它们都移动到下一行,这会留下很多空间。它应该尝试在一行中尽可能不中断或连字符来适应单词。但是很明显,即使单词可以容纳,也会产生空白。

您可以在新项目中重新创建它并观察问题。

【问题讨论】:

  • 使用label.sizeToFit()。它可能会有所帮助。
  • 还是没有帮助...
  • Apple 设计了自动换行算法来避免“寡妇”——即避免将单个单词作为段落的最后一行。在谷歌上快速搜索UILabel widows,你会发现很多讨论解释了它发生的原因,以及尝试解决它的各种方法。
  • 嗨@DonMag 感谢您为我指明正确的方向。但是它与自动换行没有任何关系,因为它在所有换行模式下都表现出相同的行为。
  • 如果你将它设置为Character Wrap,它的行为会有所不同,但当然这会在单词中间中断,我确定你不想要。 Apple 在 iOS 10 或 11 左右改变了这一点(我记得)。如果它适用于您的目的,您可以使用不可滚动、不可编辑的 UITextView 代替您的 UILabel -- 文本视图避免寡妇和孤儿(我应该说“孤儿”开头,有区别)。

标签: ios swift autolayout uikit ios-autolayout


【解决方案1】:

您可能想尝试一下...

子类UITextView,禁用滚动、编辑和选择...将textContainerInset = UIEdgeInsets.zerotextContainer.lineFragmentPadding = 0 设置为零。

结果:

代码(@IBDesignable 所以我们可以在 IB / Storyboard 中看到它):

@IBDesignable
class TextViewLabel: UITextView {

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() -> Void {
        isScrollEnabled = false
        isEditable = false
        isSelectable = false
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0
    }

}

【讨论】:

  • 非常感谢!! :)
  • @kelalaka - 哎呀......已修复。
【解决方案2】:

此代码可用于固定宽度的标签,它会克服这一点, 也可以得到标签的高度

  private static func calculateLabelProperties() -> (String, CGFloat){

    let titleString = "Your string here"

        let wordArray = titleString.components(separatedBy: " ")
        var lineCount = 1//first line denoted by 1
        var tempWidth:CGFloat = 0
        var title = ""
        for (index,element) in wordArray.enumerated() {
            let width = calculateFontSize(title: element + " ", fontName: "your font name", fontSize: 17).width
            tempWidth = tempWidth + width

            //get the nextelement
            var nextElement = ""
            if wordArray.count > index + 1 {
                nextElement = wordArray[index + 1]
            }

            let nextElementWidth = calculateFontSize(title: nextElement, fontName: "your font name", fontSize: 17).width

            if tempWidth + nextElementWidth > 410 {//410 is labelwidth
                tempWidth = 0
                lineCount += 1
                title = "\(title)\(element)\n"
            } else {
                title = "\(title)\(element) "
            }
        }
        return (title, CGFloat(lineCount * 20))//20 is label sigle line height
    }

此代码计算字体大小

func calculateFontSize(title: String, fontName: String, fontSize: CGFloat) -> (width: CGFloat, height: CGFloat){
    let font = UIFont(name: fontName, size: fontSize)
    return (title.size(OfFont: font!).width, title.size(OfFont: font!).height)
}

获取字体大小

extension String {
    func size(OfFont font: UIFont) -> CGSize {
        return (self as NSString).size(withAttributes: [NSAttributedString.Key.font: font])
    }
}

【讨论】:

    猜你喜欢
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 2013-04-01
    • 1970-01-01
    相关资源
    最近更新 更多