Last active
June 9, 2021 18:17
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
textLabel.truncate(sentence, keyword: "tigers")