Highlighting search result in UITableView cell iOS Swift
Asked Answered
B

6

7

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.

Bey answered 5/11, 2015 at 11:1 Comment(4)
what have you looked at so far? attributed strings? show your current codeWineskin
@Wineskin no i haven't done anything yet. but saw the code for attributed strings in objective c. couldn't understand.. can you help me with thisBey
Possible duplicate of Highlight the searched text in UITableView using UISearchBarGaniats
@Ganiats it doesn't have elaborate answerBey
S
14

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
Sturgis answered 4/2, 2016 at 16:1 Comment(0)
U
11

@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)
Unboned answered 12/1, 2016 at 18:40 Comment(0)
L
8

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
    }

}
Louie answered 14/5, 2019 at 11:44 Comment(0)
U
5

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!)
            }
        )
Underestimate answered 5/11, 2015 at 11:17 Comment(6)
@GaneshKumar Edited my answer.Underestimate
i have used predicates for filtering. Where should i use the code.. In the filter? or in the cellforRowatIndexPath?Bey
@GaneshKumar If you are using table view to render your search result then you have to use this as cellForRowAtIndexPath.Underestimate
@GaneshKumar If my answer is useful then accept it meta.stackexchange.com/questions/5234/…Underestimate
Let us continue this discussion in chat.Bey
@GaneshKumar Accept my answer if it's useful.Underestimate
N
0

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
  }
}
Nicotine answered 19/3, 2019 at 17:57 Comment(0)
E
0

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
    }
}
Embracery answered 16/4, 2020 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.