Skip to content

Instantly share code, notes, and snippets.

@Catherine-K-George
Last active June 9, 2021 18:17
Show Gist options
  • Save Catherine-K-George/b1cdc0fbd5ebe6a91ad88c79d4ddebd7 to your computer and use it in GitHub Desktop.
Save Catherine-K-George/b1cdc0fbd5ebe6a91ad88c79d4ddebd7 to your computer and use it in GitHub Desktop.
UILabel extension to truncate & highlight a keyword in a large sentence, add ellipsis to left & right of label
extension UILabel {
private var attributes: [NSAttributedString.Key: Any] {
return [.font: self.font ?? UIFont.systemFont(ofSize: 15)]
}
private var highlightAttributes: [NSAttributedString.Key: Any] {
return [.backgroundColor: UIColor.lightGray.withAlphaComponent(0.2), .foregroundColor: UIColor.red]
}
private var noHighlightAttributes: [NSAttributedString.Key: Any] {
return [.backgroundColor: UIColor.clear, .foregroundColor: UIColor.black]
}
func highlight(text: String, color: UIColor = .black) {
guard let txtLabel = self.text else { return }
let attributeTxt = NSMutableAttributedString(string: txtLabel)
var searchRange = NSRange(location: 0, length: attributeTxt.mutableString.length)
while searchRange.lowerBound < searchRange.upperBound {
let range: NSRange = attributeTxt.mutableString.range(of: text, options: .caseInsensitive, range: searchRange)
if range.length == 0 {
attributeTxt.addAttributes(noHighlightAttributes, range: searchRange)
break
}
attributeTxt.addAttributes(highlightAttributes, range: range)
searchRange = NSRange(location: range.upperBound, length: searchRange.upperBound - range.upperBound)
}
self.attributedText = attributeTxt
}
func truncate(_ sentence: String, keyword word: String) {
if sentence == word {
self.text = sentence
}
guard let substringRange = sentence.range(of: word, options: .caseInsensitive) else {
self.text = sentence
return
}
let nsStringSentence = NSString(string: sentence)
let nsStringSentenceRange = NSRange(location: 0, length: nsStringSentence.length)
let keywordRange = NSRange(substringRange, in: sentence)
let size: CGSize = CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let ellipsis = "..."
var shouldIncludeFrontElipsis: Bool = true
var shouldIncludeBackElipsis: Bool = true
var lastTruncatedSentence: NSString = ""
var previousTruncatedSentence: NSString = ""
var startIndex: Int = keywordRange.location
var endIndex: Int = keywordRange.upperBound
while previousTruncatedSentence.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).size.height <= self.bounds.height {
lastTruncatedSentence = previousTruncatedSentence
if startIndex == nsStringSentenceRange.lowerBound && endIndex == nsStringSentenceRange.upperBound {
break
} else {
if startIndex > nsStringSentenceRange.lowerBound {
startIndex -= 1
}
if startIndex == nsStringSentenceRange.lowerBound {
shouldIncludeFrontElipsis = false
}
if endIndex < nsStringSentenceRange.upperBound {
endIndex += 1
}
if endIndex == nsStringSentenceRange.upperBound {
shouldIncludeBackElipsis = false
}
previousTruncatedSentence = NSString(string: nsStringSentence.substring(with: NSRange(location: startIndex, length: endIndex - startIndex)))
previousTruncatedSentence = (shouldIncludeFrontElipsis ? ellipsis : "") + String(previousTruncatedSentence) + (shouldIncludeBackElipsis ? ellipsis : "") as NSString
}
}
self.text = lastTruncatedSentence as String
self.highlight(text: word)
}
}
@Catherine-K-George
Copy link
Author

Catherine-K-George commented Jun 6, 2021

textLabel.truncate(sentence, keyword: "tigers")
Screenshot 2021-06-06 at 4 54 47 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment