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.
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
}
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With