I have implemented a search bar in a TableView
. Now I want to highlight the result. For example, if I have typed two letters then those two letters should be highlighted in the resultant TableView
that drops down from the search bar. Can anyone help me to do this? I know I should use custom cells for this, but am lost implementing it.
Here is the second way to attribute text in tableview
let initialtext = "Hello World" let attrString: NSMutableAttributedString = NSMutableAttributedString(string: initialtext) let range: NSRange = (initialtext as NSString).rangeOfString(("World" , options:NSStringCompareOptions.CaseInsensitiveSearch]) attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range) cell!.textLabel?.attributedText = attrString
@Vijay has a good, correct answer for this post.
I modified this slightly for my own purposes (bolding the text in my search results) by creating a function that accepts the searchString
and the string you want to modify - the
resultString
- and returns an attributedString
that can be applied to a UILabel
.
I also had this check for the lowercaseString
attribute, so that regardless of what I typed into my search bar, my string would match the characters rather than the case (this requirement may be different, depending on your use-case).
func boldSearchResult(searchString: String, resultString: String) -> NSMutableAttributedString {
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: resultString)
let pattern = searchString.lowercaseString
let range: NSRange = NSMakeRange(0, resultString.characters.count)
let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions())
regex.enumerateMatchesInString(resultString.lowercaseString, options: NSMatchingOptions(), range: range) { (textCheckingResult, matchingFlags, stop) -> Void in
let subRange = textCheckingResult?.range
attributedString.addAttribute(NSFontAttributeName, value: UIFont.customBoldedFontNameWithSize(15.0), range: subRange!)
}
return attributedString
}
Note: I had a custom bolded font to work with, but you could always use UIFont.boldSystemFontOfSize(fontSize: CGFloat)
or something like that to get a similar effect.
Then, just add the result to your label by doing (some variation of):
cell.myCustomLabel.attributedText = boldSearchResult(mySearchText, resultString: textForBolding)
Swift 5 version of Vijayvir's answer:
let initialtext = "Hello, World!"
let attrString: NSMutableAttributedString = NSMutableAttributedString(string: initialtext)
let range = (initialtext as NSString).range(of: "World", options: .caseInsensitive)
attrString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: range)
cell.textLabel?.attributedText = attrString
Update 2020:
Here's a simple String
extension you can use to easily make an attributed string.
extension String {
func highlightText(
_ text: String,
with color: UIColor,
caseInsensitivie: Bool = false,
font: UIFont = .preferredFont(forTextStyle: .body)) -> NSAttributedString
{
let attrString = NSMutableAttributedString(string: self)
let range = (self as NSString).range(of: text, options: caseInsensitivie ? .caseInsensitive : [])
attrString.addAttribute(
.foregroundColor,
value: color,
range: range)
attrString.addAttribute(
.font,
value: font,
range: NSRange(location: 0, length: attrString.length))
return attrString
}
}
You could achieve this by find the search term string range from your result string and adding attributed string at that range. Find the sample code below,
Objective-C
NSString *searchTerm = /* SEARCH_TERM */;
NSString *resultText = /* YOUR_RESULT_TEXT */;
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:resultText];
NSString *pattern = [NSString stringWithFormat:@"(%@)", searchTerm];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:kNilOptions error:nil];
NSRange range = NSMakeRange(0, resultText.length);
[regex enumerateMatchesInString:resultText options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange subStringRange = [result rangeAtIndex:1];
[attributedString addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:subStringRange];
}];
Swift (TESTED)
let searchTerm = "" /* SEARCH_TERM */
let resultText = "" /* YOUR_RESULT_TEXT */
let attributedString:NSMutableAttributedString = NSMutableAttributedString(string: resultText)
let pattern = "(\(searchTerm))"
let range:NSRange = NSMakeRange(0, resultText.characters.count)
let regex = try! NSRegularExpression( pattern: pattern, options: NSRegularExpressionOptions())
regex.enumerateMatchesInString(
resultText,
options: NSMatchingOptions(),
range: range,
usingBlock: {
(textCheckingResult, matchingFlags, stop) -> Void in
let subRange = textCheckingResult?.range
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: subRange!)
}
)
cellForRowAtIndexPath
. –
Underestimate Tried to keep it as slim as possible. The function returns an attributed string with searchText occurrences in bold. Swift 4.2+
private func boldedString(with baseString: String, searchString: String, fontSize: CGFloat) -> NSAttributedString? {
guard let regex = try? NSRegularExpression(pattern: searchString, options: .caseInsensitive) else {
return nil
}
let attributedString = NSMutableAttributedString(string: baseString)
let boldFont = UIFont.systemFont(ofSize: fontSize, weight: .bold)
regex
.matches(in: baseString, options: .withTransparentBounds,
range: NSRange(location: 0, length: baseString.utf16.count))
.forEach {
attributedString.addAttributes([.font: boldFont], range: $0.range)
}
return attributedString
}
In the cell you will need to add code like this for configuration:
func configure(with text: String, searchText: String?) {
if let boldedAddress = boldedString(with: text,
searchString: searchText,
fontSize: titleLabel.font.pointSize) {
titleLabel.attributedText = boldedAddress
} else {
titleLabel.text = locationInfo.location.address
}
}
This solution works with escaped characters Like ({}[]()'") this solution written in SWIFT 5.
func generateAttributedString(with searchTerm: String, targetString: NSAttributedString) -> NSAttributedString? {
let attributedString = NSMutableAttributedString(attributedString: targetString)
do {
let regex = try NSRegularExpression(pattern: NSRegularExpression.escapedPattern(for: searchTerm).trimmingCharacters(in: .whitespacesAndNewlines).folding(options: .regularExpression, locale: .current), options: .caseInsensitive)
let range = NSRange(location: 0, length: targetString.string.utf16.count)
attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.clear, range: range)
for match in regex.matches(in: targetString.string.folding(options: .regularExpression, locale: .current), options: .withTransparentBounds, range: range) {
attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.yellow, range: match.range)
}
return attributedString
} catch {
NSLog("Error creating regular expresion: \(error)")
return nil
}
}
© 2022 - 2024 — McMap. All rights reserved.