【问题标题】:How to make multi-line UILabel text fit within predefined width without wrapping mid-word如何使多行 UILabel 文本适合预定义的宽度而不换行中间字
【发布时间】:2017-03-19 19:10:31
【问题描述】:

我在 Interface Builder 中精心布置了一个 UILabel,并具有适当的高度和宽度限制。行数设置为 4。换行设置为自动换行。文本为“已检查”。字体非常大,因此它只适合“CHECKE”,而“D”在第二行。写“Checked”而不是“CHECKED”可以让字体缩小(如预期的那样),以便整个单词适合。但是(文本是用户给定的,并且可以预期用户编写完全大写的单词)具有大写单词的标签不会破坏它/按预期缩小字体。

您对我可能遗漏的内容有什么建议吗?将单词大写(因此只有第一个字母大写)确实有效,但不是客户想要的。

更新问题

这个问题似乎与大写或小写文本无关。我的问题可以通过回答以下问题来解决:

如何(理想情况下仅借助 Interface Builder)使 UILabel 文本缩小以尝试在所有可用行中容纳完整的单词而不将文本中间字换行?

  • 如果文本“CHECKED”对于标签来说太宽(有超过 1 行可用),它应该缩小字体大小,而不是破坏“D”并将单个字母换行到下一行。
  • 如果文本是“一个 CHECKED 两个”并且单个单词“CHECKED”对于标签来说已经太宽(有超过 1 行可用),它应该在所有单词之间中断缩小字体大小,以便“CHECKED”仍然适合中间线。

避免:

one
CHECKE
D two

非常感谢!

【问题讨论】:

    标签: ios swift interface-builder uilabel


    【解决方案1】:

    这是一个UILabel 子类,它将在标签text 中找到最大的单词,使用NSStringboundingRect 函数查看该单词在当前字体下的大小,然后删除字体大小直到它适合宽度。

    class AutosizingMultilineLabel: UILabel {
        override func layoutSubviews() {
            super.layoutSubviews()
            self.adjustFontToFitWidth()
        }
        
        func adjustFontToFitWidth() {
            guard let currentFont = self.font else { return }
            let minimumFontSize: CGFloat = floor(self.minimumScaleFactor * currentFont.pointSize)
            
            var newFontSize = currentFont.pointSize
            var theNewFont = currentFont
            
            if let text = self.text, let longestWord = text.components(separatedBy: " ").max(by: {$1.count > $0.count})?.replacingOccurrences(of: "\n", with: "") {
                let nsString = longestWord as NSString
                
                while newFontSize > minimumFontSize {
                    theNewFont = currentFont.withSize(newFontSize)
                    
                    let boundingRect = nsString.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude),
                                                             options: NSStringDrawingOptions.usesLineFragmentOrigin,
                                                             attributes: [.font: theNewFont],
                                                             context: nil)
                    
                    if ceil(boundingRect.size.width) <= self.bounds.size.width {
                        break
                    }
                    newFontSize -= 1
                }
                
                self.font = theNewFont
            }
        }
    }
    

    【讨论】:

    • 这实际上相当不错。虽然我会警告它是通过字符数来确定最长的单词,但例如,当“WOW”在水平维度上比“jilt”长时。此外,支持小数字体大小,所以我会修改newFontSize 用一个像这样的乘数newFontSize *= 0.95而不是减去1。字体大小10和9之间的长度差异在视觉上看起来大于20和19之间的差异,即使它们是相同的差异。那么你不需要floor最小字体大小。while 应该是&gt;= 而不仅仅是&gt;
    • 这是唯一对我有用的解决方案,向你的方向发送爱,Ric!谢谢
    【解决方案2】:

    当单词大于行时,自动换行不起作用。如果它不适合这一行,它将不适合下一行。 (相同的字,相同的大小,相同的行大小)。为了使它适合,标签将开始在下一行放置字母。

    如果您在标签上允许多行,操作系统会在调整字体大小之前尝试填充这些行。

    【讨论】:

    • 它以我想要的方式工作,“Checked”也比线大。它会缩小字体大小,而不是将字母放在下一行。如何使它与“CHECKED”一样?
    • 我似乎无法复制这种效果。如果单词大于行并且标签仍然有行可用,它将按字母将单词分开,然后缩小字体大小。 (无论我使用“已检查”还是“已检查”)
    • 按照@DonMag 的例子,UILabel 似乎对“Checked”和“CHECKED”都做了同样的事情。由于某种原因,它不适用于我的设置。我想“已检查”稍微窄一些,并且完全适合 UILabel 的宽度。我将更新问题:有没有办法在不将单词的单个字母放入下一行的情况下自动缩小字体大小?
    【解决方案3】:

    我认为您只是遇到了 Autoshrink 的限制。

    在界面生成器中:

    • 使用Width: 230Height: 280 添加新的UILabel
    • 将字体设置为System 44.0
    • 设置Line Break: Truncate Tail
    • Autoshrink: Minimum Font Scale 设置为0.15
    • 将标签的文本设置为test CHECKED lines

    现在,左右拖动标签右边缘的手柄...当它变得太窄时,单词CHECKED 将中断到下一行。

    CHECKED 更改为checked 并做同样的事情。您应该会看到相同的行为。

    现在,尝试上下拖动底部边缘。使用CHECKEDchecked,您应该看到字体大小自动缩小。

    所以...要执行您想要执行的操作,您可能必须跳过 Autoshrink 而是进行一些代码计算。

    编辑:进一步了解正在发生的事情...

    • 从上面的值开始,但将标签的 Height 设置为 170 - 只给它一点垂直填充。
    • 现在,拖动左边缘使其变窄。
    • 当您到达单词 CHECKED 的末尾并继续前进时,您会看到字体缩小,直到它变得足够小以至于有空间可以换行到第 4 行。

    我认为您将需要一些代码来获得您所需要的。

    【讨论】:

    • 谢谢!我已经更新了我的问题(见上文)。有没有办法避免中间词换行?
    • @Dr.Cashberg - 我已经编辑了我的答案...看起来除了约束和 IB 设置之外,您还需要代码。
    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多