【问题标题】:How to limit the number of characters in a String or attributed String in Swift如何在 Swift 中限制字符串或属性字符串中的字符数
【发布时间】:2017-04-12 20:52:26
【问题描述】:

Given 是一个 (html) 字符串,其中包含 x 个字符。字符串将被格式化为属性字符串。然后显示在UILabel

UILabel 的高度为 >= 25<= 50,以将行数限制为 2。

由于字符串具有在格式化的属性字符串中不可见的字符,例如<b> / <i>,因此最好的方法是限制属性字符串的字符数。

UILabel 属性 .lineBreakMode = .byTruncatingTail 导致单词被剪切。

目标,如果字符数超过UILabel 中的空间限制,则在单词之间切换。需要maxCharacterCount = 50。确定maxCharacterCount 之前的最后一个space。剪切字符串并将... 添加为UILabel 的最后一个字符。

限制字符的最佳方法是什么?非常感谢您的帮助。

【问题讨论】:

  • 您自己尝试过什么吗?或者也许我没有正确理解这个问题。如果您限制标签的大小,则字符串将自动截断
  • UILabel 在标签上设置lineBreakMode 属性来处理它。请参阅UILabel documentation中的“自定义标签外观”
  • @LinusG。我当然知道,但重点是,例如字符串有 200 个字符,将其剪切为 47 并附加 3x .,但也许 lineBreakMode 会这样做.. 立即签出
  • 但是如果标签会自动为您添加三个点,为什么还要手动添加呢?或者您是否需要点不仅在视觉上而且实际上是字符串的一部分?
  • 查看我的编辑。首先,我并不真正了解自动可能性,但删减词并不完全是我想要的。我想让它在单词之间切割。所以在所需字符数之前的最后一个"space" 替换为3x ...

标签: swift string


【解决方案1】:

从完整的字符串和已知的标签的两行高度及其已知宽度开始,并继续从字符串的末尾剪切单词,直到在该宽度处,字符串的高度小于标签的高度。然后在结尾处再删掉一个单词,添加省略号,并将生成的字符串放入标签中。

这样,我得到了这个:

注意“时间”后面的单词从不开始;我们在插入省略号的精确词尾处停止。我是这样做的:

    lab.numberOfLines = 2
    let s = "Little poltergeists make up the principle form of material " +
        "manifestation. Now is the time for all good men to come to the " +
        "aid of the country."
    let atts = [NSFontAttributeName: UIFont(name: "Georgia", size: 18)!]
    let arr = s.components(separatedBy: " ")
    for max in (1..<arr.count).reversed() {
        let s = arr[0..<max].joined(separator: " ")
        let attrib = NSMutableAttributedString(string: s, attributes: atts)
        let height = attrib.boundingRect(with: CGSize(width:lab.bounds.width, 
                                                      height:10000),
                                         options: [.usesLineFragmentOrigin],
                                         context: nil).height
        if height < lab.bounds.height {
            let s = arr[0..<max-1].joined(separator: " ") + "…"
            let attrib = NSMutableAttributedString(string: s, attributes: atts)
            lab.attributedText = attrib
            break
        }
    }

当然可以更加更复杂地了解什么是“单词”和测量条件,但以上展示了此类事物的一般常用技术,应该就足够了让你开始。

【讨论】:

  • 这太棒了。非常感谢您的努力
  • 这样会丢失原始字符串的信息。只要 UILabel 不改变,外观就可以了。例如,如果您旋转设备,您的三个点就会出现在错误的位置。
  • @GiuseppeLanza 我完全同意您必须在标签更改范围时再次执行此操作。基本上,OP 要求手动执行布局,以代替标签和 Text Kit 已经执行的操作。 — 如果保留原始字符串,就不会丢失它。我的代码不是“最终答案”,它只是演示了一种以 OP 描述的方式更改字符串的简单技术。这甚至不是正确的答案; 真正的 解决方案是使用带有自定义文本工具包堆栈的不可编辑 UITextView 并在那里自己执行布局。
  • 但是你的回答,回答了我的问题,解决了我的问题,因此你已经回答了,即使你不会称之为“正确答案”:-)
【解决方案2】:

试试这个:

import UIKit

class ViewController: UIViewController {
var str = "Hello, playground"
var thisInt = 10
@IBOutlet weak var lbl: UILabel!
var lblWidth : CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    lblWidth = lbl.bounds.width

    while str.characters.count <= thisInt - 3 {
        str.remove(at: str.index(before: str.endIndex))
        str.append("...")
    }
    lbl.text = str
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

string width calculation link

【讨论】:

  • 这是一个简短而快速的想法,但由于字符串包含&lt;b&gt; 之类的元素,因此标签的最终内容可能看起来比预期的想法太短。
【解决方案3】:

只是为了记录Matt's answer 是正确的,但是您可以通过创建自己的 UILabel 子类来消除任何可能的问题,它将原始值存储在变量中。当方向改变时,您可以从视图控制器更新其布局。

【讨论】:

  • 我现在并没有真正从您的方法中受益。您能否更具体地说明您认为“可能的问题”?以及您将存储什么值
  • 看你将有一个原始值,你将存储在变量中,例如“Marry had a little lamb”。其他部分是设置将被剪切的文本,例如“结婚了……”。对于可能的问题,我的意思是当您使用自定义标签时,您无法从默认 UILabel 检索原始文本,因为您存储了原始值。这就是我想说的。您不必将它存储在您的 VC 或其他任何地方,但您的自定义标签会为您保存它。所以旋转或调整大小不会有任何问题,因为你总是可以重新计算。
【解决方案4】:

快速更正Mikael Weiss 的答案。

if str.count > thisInt +3{
    while str.count >= thisInt {
        str.remove(at: str.index(before: str.endIndex))
    }
    str.append("...")
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-17
    • 2021-08-12
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2018-10-13
    • 1970-01-01
    相关资源
    最近更新 更多