多行UILabel - 突出显示某个范围并截断以使其可见

时间:2016-08-07 11:22:22

标签: ios objective-c swift cocoa-touch uilabel

我目前正在开发我的某个应用中的搜索功能,但我仍然试图解决一个非常烦人的问题。

让我们假设我有以下两段文字:

  

Lorem ipsum dolor坐下来,精神上的精神。在blandit proin commodo tristique lectus。 Vivamus felis odio,laoreet in lorem eget,mattis imperdiet lorem。

     

Duis in nibh eleifend,lobortis mauris a,egestas odio。

当用户执行搜索时,我将使用表格视图显示结果。此表格视图中的单元格显示2行文本。为了突出显示匹配的字符,我使用属性文本和设置粗体字符来匹配字符。

这一切都运作良好。但是,我有一个与截断有关的问题。让我们假设用户搜索“egestas odio”。这些单词位于字符串的最后,显然,我想显示整个字符串并截断它的头部。

不幸的是,我无法做到这一点。即使我为NSMutableParagraphStyle设置了正确的截断,我将其添加为我的属性字符串的属性,但它不起作用。我看到标签的开头,尾部是截头而不是头部。

我已经发现如果删除所有换行符,这个问题就会得到解决。但是,在我的情况下,这不太实用。

有人知道如何克服这个障碍吗?或者,也许你可以给我一些关于如何以稍微不同的方式实现我需要的功能的一般建议。这似乎相当普遍,很可能有一些开源库有助于实现这一目标。不幸的是,到目前为止我找不到任何东西。

提前致谢!

1 个答案:

答案 0 :(得分:0)

给定一个字符串和一个你想保留的范围,它从任一边走进,直到截断的字符串适合给定的大小。您需要做额外的工作来重新计算截断字符串中的范围。

Swift 4

func truncatedString(for text: String, with attributes: [NSAttributedStringKey: Any], constrainedTo size: CGSize, keeping range: Range<String.Index>?) -> String {

    let nsString = NSString(string: text)

    var nsRange = NSMakeRange(nsString.length / 2, 0)
    if let range = range {
        nsRange = NSRange(range, in: text)
    }

    var truncatedString = nsString

    let elipsis = "..."
    let elipsisWidth = elipsis.size(withAttributes: attributes).width

    var shouldAddFrontElipsis = false
    var shouldAddBackElipsis = false

    var constrainedWidthIncludingElipsis = size.width
    if nsRange.location > 0 {
        shouldAddFrontElipsis = true
        constrainedWidthIncludingElipsis -= elipsisWidth
    }

    if NSMaxRange(nsRange) < nsString.length {
        shouldAddBackElipsis = true
        constrainedWidthIncludingElipsis -= elipsisWidth
    }

    var startIndex = 0
    var endIndex = nsString.length

    while (truncatedString.boundingRect(with: CGSize(width: constrainedWidthIncludingElipsis, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: attributes, context: nil).size.height > size.height) {

        if startIndex == nsRange.location && endIndex == NSMaxRange(nsRange) {
            break
        } else {

            if startIndex < nsRange.location {
                startIndex += 1
            }

            if endIndex > NSMaxRange(nsRange) {
                endIndex -= 1
            }

            truncatedString = NSString(string: nsString.substring(with: NSMakeRange(startIndex, endIndex - startIndex)))
        }
    }

    if startIndex == 0 {
        shouldAddFrontElipsis = false
    }

    if endIndex == nsString.length {
        shouldAddBackElipsis = false
    }

    return (shouldAddFrontElipsis ? elipsis : "") + String(truncatedString) + (shouldAddBackElipsis ? elipsis : "")
}