Derek Soike
Derek Soike

Reputation: 11670

Make part of a string bold that matches a search string

I have a table of items and each item has a label. I also have a search bar that is used to filter the items in the table based on whether mySearchBar.text is a substring of myLabel.text.

That is all working fine, but I'd like to bold the portions of label text that match the search string.

The end product would be something similar to Google Maps search.

enter image description here

Upvotes: 5

Views: 3180

Answers (2)

Yash Bedi
Yash Bedi

Reputation: 1355

Swift 4 : XCode 9.x

private func filterAndModifyTextAttributes(searchStringCharacters: String, completeStringWithAttributedText: String) -> NSMutableAttributedString {

    let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: completeStringWithAttributedText)
    let pattern = searchStringCharacters.lowercased()
    let range: NSRange = NSMakeRange(0, completeStringWithAttributedText.characters.count)
    var regex = NSRegularExpression()
    do {
        regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options())
        regex.enumerateMatches(in: completeStringWithAttributedText.lowercased(), options: NSRegularExpression.MatchingOptions(), range: range) {
            (textCheckingResult, matchingFlags, stop) in
            let subRange = textCheckingResult?.range
            let attributes : [NSAttributedStringKey : Any] = [.font : UIFont.boldSystemFont(ofSize: 17),.foregroundColor: UIColor.red ]
            attributedString.addAttributes(attributes, range: subRange!)
        }
    }catch{
        print(error.localizedDescription)
    }
    return attributedString
}

How to use :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = UITableViewCell(style: .subtitle , reuseIdentifier: "Cell")
     cell.textLabel?.attributedText = self.filterAndModifyTextAttributes(searchStringCharacters: self.textFromSearchBar, completeStringWithAttributedText: searchResultString)
     return cell

}

RESULT

Upvotes: 9

Derek Soike
Derek Soike

Reputation: 11670

Here's a sample of what I ended up implementing:

@IBOutlet weak var mySearchBar: UISearchBar!
@IBOutlet weak var myLabel: UILabel!

...

func makeMatchingPartBold(searchText: String) {

    // check label text & search text
    guard
        let labelText = myLabel.text,
        let searchText = mySearchBar.text
    else {
        return
    }

    // bold attribute
    let boldAttr = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: myLabel.font.pointSize)]

    // check if label text contains search text
    if let matchRange: Range = labelText.lowercased().range(of: searchText.lowercased()) {

        // get range start/length because NSMutableAttributedString.setAttributes() needs NSRange not Range<String.Index>
        let matchRangeStart: Int = labelText.distance(from: labelText.startIndex, to: matchRange.lowerBound)
        let matchRangeEnd: Int = labelText.distance(from: labelText.startIndex, to: matchRange.upperBound)
        let matchRangeLength: Int = matchRangeEnd - matchRangeStart

        // create mutable attributed string & bold matching part
        let newLabelText = NSMutableAttributedString(string: labelText)
        newLabelText.setAttributes(boldAttr, range: NSMakeRange(matchRangeStart, matchRangeLength))

        // set label attributed text
        myLabel.attributedText = newNameText
    }
}

Upvotes: 4

Related Questions