Keep hyperlink to specific word in UITextView using attributedString - ios

I'm trying to implement an editor that can handle hashtag while typing.
extension UITextView {
func resolveHashTags() {
if self.text.isEmpty {
let emptyString = NSMutableAttributedString(string: " ", attributes: [NSAttributedString.Key.foregroundColor: UIColor.black,
NSAttributedString.Key.font: self.font!])
self.attributedText = emptyString
self.textColor = .black
self.text = ""
return
}
let cursorRange = selectedRange
let nsText = NSString(string: self.text)
let words = nsText.components(separatedBy: CharacterSet(charactersIn: "##ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_").inverted).filter({!$0.isEmpty})
self.textColor = .black
let attrString = NSMutableAttributedString()
attrString.setAttributedString(self.attributedText)
attrString.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.black], range: nsText.range(of: self.text))
var anchor: Int = 0
for word in words {
// found a word that is prepended by a hashtag!
// homework for you: implement #mentions here too.
let matchRange:NSRange = nsText.range(of: word as String, range: NSRange(location: anchor, length: nsText.length - anchor))
anchor = matchRange.location + matchRange.length
if word.hasPrefix("#") {
// a range is the character position, followed by how many characters are in the word.
// we need this because we staple the "href" to this range.
// drop the hashtag
let stringifiedWord = word.dropFirst()
if let firstChar = stringifiedWord.unicodeScalars.first, NSCharacterSet.decimalDigits.contains(firstChar) {
// hashtag contains a number, like "#1"
// so don't make it clickable
} else {
// set a link for when the user clicks on this word.
// it's not enough to use the word "hash", but you need the url scheme syntax "hash://"
// note: since it's a URL now, the color is set to the project's tint color
attrString.addAttribute(NSAttributedString.Key.link, value: "hash:\(stringifiedWord)", range: matchRange)
}
} else if !word.hasPrefix("#") {
}
}
self.attributedText = attrString
self.selectedRange = cursorRange
}
}
So this is the extension I'm using to create a hyperlink in UITextView. Called in func textViewDidChange(_ textView: UITextView)
So while typing if any word starts with #. It'll turn in hyperlinks and will change color to blue. After typing the intended word if you press space it goes back to black text. This is expected behavior.
But if you clear text and move your course back to hashtag word like this
it keeps extending hyperlink to the next word too.
any solution to keep hyperlinks to that word only. Anything typed after hashtag should be normal text

I finally figured it out.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
var shouldReturn = true
let selectedRange = textView.selectedRange
let attributedText = NSMutableAttributedString(attributedString: textView.attributedText)
if !text.isEmpty && text != " " {
var userAttributes = [(NSAttributedString.Key, Any, NSRange)]()
attributedText.enumerateAttribute(.link, in: _NSRange(location: 0, length: textView.text.count), options: .longestEffectiveRangeNotRequired) { (value, range, stop) in
if let url = value as? String, url.hasPrefix("user:") {
userAttributes.append((.link, value!, range))
}
}
if let userLink = userAttributes.first(where: {$0.2.contains(range.location - 1)}) {
attributedText.replaceCharacters(in: range, with: NSAttributedString(string: text, attributes: [NSAttributedString.Key.link : userLink.1, NSAttributedString.Key.font : textView.font as Any]))
textView.attributedText = attributedText
shouldReturn = false
} else {
attributedText.replaceCharacters(in: range, with: NSAttributedString(string: text, attributes: [NSAttributedString.Key.font : textView.font as Any]))
textView.attributedText = attributedText
textDidChange?(textView)
shouldReturn = false
}
textView.selectedRange = _NSRange(location: selectedRange.location + text.count, length: 0)
textViewDidChange(textView)
}
return shouldReturn
}
This way I have the control to update the link in between the word and it doesn't extend afterward to a new word.

Related

NSAttributedString not working for UILabel

I looked around SO and couldn't find this exact problem, despite there being a few questions with similar titles.
All I want to do is have some matching text on UILabel be drawn in BOLD. I'm using it when I'm searching for objects, it should 'bolden' the search term. To this aim, I wrote the following code:
extension String {
func boldenOccurrences(of searchTerm: String?, baseFont: UIFont, textColor: UIColor) -> NSAttributedString {
let defaultAttributes: [String : Any] = [NSForegroundColorAttributeName : textColor,
NSFontAttributeName: baseFont]
let result = NSMutableAttributedString(string: self, attributes: defaultAttributes)
guard let searchTerm = searchTerm else {
return result
}
guard searchTerm.characters.count > 0 else {
return result
}
// Ranges. Crash course:
//let testString = "Holy Smokes!"
//let range = testString.startIndex ..< testString.endIndex
//let substring = testString.substring(with: range) // is the same as testString
var searchRange = self.startIndex ..< self.endIndex //whole string
var foundRange: Range<String.Index>!
let boldFont = UIFont(descriptor: baseFont.fontDescriptor.withSymbolicTraits(.traitBold)!, size: baseFont.pointSize)
repeat {
foundRange = self.range(of: searchTerm, options: .caseInsensitive , range: searchRange)
if let found = foundRange {
// now we have to do some stupid stuff to make Range compatible with NSRange
let rangeStartIndex = found.lowerBound
let rangeEndIndex = found.upperBound
let start = self.distance(from: self.startIndex, to: rangeStartIndex)
let length = self.distance(from: rangeStartIndex, to: rangeEndIndex)
log.info("Bolden Text: \(searchTerm) in \(self), range: \(start), \(length)")
let nsRange = NSMakeRange(start, length)
result.setAttributes([NSForegroundColorAttributeName : textColor,
NSFontAttributeName: boldFont], range: nsRange)
searchRange = found.upperBound ..< self.endIndex
}
} while foundRange != nil
return result
}
}
Everything "looks" fine. The log statement spits out what I expect and it's all good. However, when drawn on the UILabel, sometimes an entire string is set to bold, and I don't understand how that could be happening. Nothing in the code suggests this should be happening.
I set the result of this above method in a typical UITableCell configuration method (i.e. tableView(cellForRowAt indexPath:.... ) )
cell.titleLabel.attributedText = artist.displayName.emptyIfNil.boldenOccurrences(of: source.currentSearchTerm, baseFont: cell.titleLabel.font, textColor: cell.titleLabel.textColor)
Your primary issue is the cell reuse, maybe when a cell is reused keep your font bold as font, and that is why you have this issue, you can solve this in your cell prepareForReuse() method you can add
override func prepareForReuse() {
super.prepareForReuse()
//to fix ipad Error
self.titleLabel.font = UIFont(name: "YourBaseFont", size: yourFontSize)
}

Swift - NSMutableAttributedString changes all text in UITextView

Download an example I have created
Example Link
I am adding a link to my UITextView like this:
let systemFont = self.text.font!
let linkAttributes = [
NSFontAttributeName : systemFont,
NSLinkAttributeName: NSURL(string: alertController.textFields![0].text!)!] as [String : Any]
let myAttributes2 = [ NSForegroundColorAttributeName: customGreen]
let attributedString = NSMutableAttributedString(string: "\(urlName)")
// Set the 'click here' substring to be the link
attributedString.setAttributes(linkAttributes, range: NSMakeRange(0, urlName.characters.count))//(0, urlName.characters.count))
self.text.linkTextAttributes = myAttributes2
self.text.textStorage.insert(attributedString, at: self.text.selectedRange.location)
let cursor = NSRange(location: self.text.selectedRange.location + "\(urlName)".characters.count, length: 0)
self.text.selectedRange = cursor
// self.text.font = systemFont
But after inserting it, it changes all the current text in the UITextView to the same font.
So for example if I have some text that is Bold and some more text that is Italic, after I add the url(which is system font) it resets all the bold/italic text to the system font....
If anyone knows how to keep the current font of the previous text I'd really appreciate the help.
For any further explanation just drop a comment below!
Many thanks in advance to anyone that can help!
Update
I am changing the text here in textDidChange
if text == " "
{
// let systemFont = self.text.font!
// let linkAttributes = [NSFontAttributeName : systemFont]
let attributes = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: self.text.font!] as [String : Any]
let attributedString = NSMutableAttributedString(string: text, attributes: attributes)
self.text.textStorage.insert(attributedString, at: range.location)
let cursor = NSRange(location: self.text.selectedRange.location+1, length: 0)
textView.selectedRange = cursor
return false
}
I have that so after adding the URL I make a space and reset the font so I don't continue typing as a URL link...Probably the problem but when I type normal and don't set a url link the text doesn't changing while make a space...
let urlName = "google"
#IBAction func btnPressed(_ sender: Any) {
let systemFont = UIFont.systemFont(ofSize: 11)
let linkAttributes = [
NSFontAttributeName : systemFont,
NSLinkAttributeName: NSURL(string: "https://www.google.com")!] as [String : Any]
let myAttributes2 = [NSForegroundColorAttributeName: UIColor.green]
let attributedString = NSMutableAttributedString(string: "\(urlName)")
attributedString.setAttributes(linkAttributes, range: NSMakeRange(0, urlName.characters.count))//(0, urlName.characters.count))
self.text.linkTextAttributes = myAttributes2
self.text.textStorage.insert(attributedString, at: self.text.selectedRange.location)
let cursor = NSRange(location: self.text.selectedRange.location + "\(urlName)".characters.count, length: 0)
self.text.selectedRange = cursor
}
This is how you should update the textView if you want to add text programmatically.
Do not use the textViewDidChange(_:) delegate method in this situation.
UPDATE
I've downloaded your code from dropbox and made some changes to it.
so here I'm changing the textView text in viewDidLoad() for example.
I've created two constants in order to use them again in the code, fontAttr is the original font with the name and size and fontColorAttrBlue is the original font color.
let fontAttr = UIFont(name: "Helvetica-Bold", size: 20)
let fontColorAttrBlue = UIColor.blue
override func viewDidLoad() {
super.viewDidLoad()
let attrString = NSMutableAttributedString(string: "Hello World, How are you?", attributes: [NSFontAttributeName : fontAttr!, NSForegroundColorAttributeName: fontColorAttrBlue ])
self.textView.delegate = self // you can set the delegate from the storyboard.
self.textView.attributedText = attrString
}
And I've deleted this line of code self.textView.font = systemFont from webLink(_ sender: AnyObject) action method, so that it wouldn't change the font of the textView.
And lastly in textView(_:shouldChangeTextIn:replacementText:) method instead of checking if the user has entered " " String I'm checking if the user has entered any String and reusing the font attributes that I created in the beginning, so that if the user enters any kind of text after the link it would be the original text and not the one assigned for the like text.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text.characters.count > 0 {
let attributedString = NSMutableAttributedString(string: text, attributes: [NSFontAttributeName : self.fontAttr!, NSForegroundColorAttributeName: self.fontColorAttrBlue])
self.textView.textStorage.insert(attributedString, at: range.location)
let cursor = NSRange(location: self.textView.selectedRange.location+1, length: 0)
textView.selectedRange = cursor
return false
}
return true
}

How am I able to highlight words with multiple colors in UITextVIew with NSAtrributedString?

This has been bugging me for a long time. As the title says, I do not see any other way to come with an idea to highlight some particular words with various colors. For example, if I have an array that contains words, "hello", "awesome", "hungry", "sky"...and so on. Then in the code below, it just highlights these words inside the array with one color, which is set by NSBackgroundColorAttributeName. So my best solution so far, which failed, was to create multiple of the same method. So I made several highlightColors methods and entered an array in each method and changed different color for each.
A word entered on my TextView became blue. After another word from another array was entered on my TextView, the newly entered word became red but the previous word were not highlighted anymore. I want all words from different arrays to remain highlighted differently. I never want their colors to disappear. I just cannot come up with this idea for a week. Could you please help me out with this?
func highlightColors(type: [String]){
let attrStr = NSMutableAttributedString(string: myTextView.text)
let inputLength = attrStr.string.characters.count
let searchString : NSArray = NSArray.init(array: type)
for i in 0...searchString.count-1 {
let string : String = searchString.object(at: i) as! String
let searchLength = string.characters.count
var range = NSRange(location: 0, length: attrStr.length)
while (range.location != NSNotFound) {
range = (attrStr.string as NSString).range(of: string, options: [], range: range)
if (range.location != NSNotFound) {
coloredStringArray.append(string)
attrStr.addAttribute(NSBackgroundColorAttributeName, value: UIColor.blue, range: NSRange(location: range.location, length: searchLength))
attrStr.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 20), range: range)
range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
myTextView.attributedText = attrStr
myTextView.font = UIFont(name: "times new roman", size: 20.0)
}
}
}
}
Here is an example of using NSAttributedString to highlight certain words with certain colours. You can modify it any way you want to highlight with certain fonts and backgrounds, etc.
The idea is that you search the text view's text for a string then modify its attributed string with the required attributes.
The reason your attributes are probably disappearing when you edit the textView is because you are using textView.text = blah..
private var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView = UITextView()
self.view.addSubview(self.textView)
self.textView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.textView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
self.textView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.textView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
self.textView.translatesAutoresizingMaskIntoConstraints = false
self.textView.text = "Test Highlighting Colors on StackOverflow."
self.highlight(text: ["Test", "Highlighting", "Colors", "StackOverflow", "Test"], colours: [UIColor.red, UIColor.blue, UIColor.green, UIColor.purple, UIColor.cyan])
}
func highlight(text: [String], colours: [UIColor]) {
var ranges = Array<Int>()
let attrString = self.textView.attributedText.mutableCopy() as! NSMutableAttributedString
for i in 0..<text.count {
let str = text[i]
let col = colours[i]
var range = (self.textView.text as NSString).range(of: str)
while (range.location != NSNotFound && ranges.index(of: range.location) != nil) {
let subRange = NSMakeRange(range.location + 1, self.textView.text.characters.count - range.location - 1)
range = (self.textView.text as NSString).range(of: str, options: NSString.CompareOptions.literal, range: subRange)
}
if range.location != NSNotFound {
ranges.append(range.location)
attrString.addAttribute(NSForegroundColorAttributeName, value: col, range: range)
}
}
self.textView.attributedText = attrString
}

AttributedText in TextView while typing [duplicate]

This question already has answers here:
Replace UITextViews text with attributed string
(4 answers)
Closed 6 years ago.
I have a textView, and I am trying to give it an attributed text. I tried achieving it inside shouldChangeTextInRange, but it crashes for range out of index.
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if myTextView {
textView.attributedText = addAttributedText(1, text: text, fontsize: 13)
let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
let numberOfChars = newText.characters.count
return numberOfChars < 20
}
return true
}
func addAttributedText(spacing:CGFloat, text:String, fontsize: CGFloat) -> NSMutableAttributedString {
let attributedString = NSMutableAttributedString(string: text, attributes: [NSFontAttributeName:UIFont(
name: "Font",
size: fontsize)!])
attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSMakeRange(0, text.characters.count))
return attributedString
}
I tried adding attributedString with empty text to textView in viewDidLoad, but that doesn't help. That's why I thought it would be appropriate to do it on shouldChangeTextInRange
(Please note that my addAttributedText method works perfectly for other textviews)
If I use this, in one character type-in, it writes 2x and crashes. What is the right way of handling that kind of converting textView's text to attributed text that is being typed.
Here is the code that I tried to convert from the link above, it might have bugs, but I hope it will be able to help you.
func formatTextInTextView(textView: UITextView)
{
textView.scrollEnabled = false
var selectedRange: NSRange = textView.selectedRange
var text: String = textView.text!
// This will give me an attributedString with the base text-style
var attributedString: NSMutableAttributedString = NSMutableAttributedString(string: text)
var error: NSError? = nil
var regex: NSRegularExpression = NSRegularExpression.regularExpressionWithPattern("#(\\w+)", options: 0, error: error!)
var matches: [AnyObject] = regex.matchesInString(text, options: 0, range: NSMakeRange(0, text.length))
for match: NSTextCheckingResult in matches {
var matchRange: NSRange = match.rangeAtIndex(0)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: matchRange)
}
textView.attributedText = attributedString
textView.selectedRange = selectedRange
textView.scrollEnabled = true
}
EDIT: didn't see that in the original post there was a Swift answer, here is the link: stackoverflow.com/a/35842523/1226963

How to make UITextView detect hashtags?

I know that the UITextView default can detect URL, but how can i make it detect hashtags(#)?
It doesn't needs to detect hashtags while typing, but then viewDidLoad the text is set in the UITextView, so i want to detect hashtags as a color or something.
I have been using ActiveLabel, but that is only for UILabel, and i need the scroll function that the UITextView has.
This should work for you
Create a new swift file with any name(UITextViewHashtagExtension.swift)
Insert this code below:
import UIKit
extension UITextView {
func resolveHashTags(){
// turn string in to NSString
let nsText:NSString = self.text
// this needs to be an array of NSString. String does not work.
let words:[NSString] = nsText.componentsSeparatedByString(" ")
// you can't set the font size in the storyboard anymore, since it gets overridden here.
let attrs = [
NSFontAttributeName : UIFont.systemFontOfSize(17.0)
]
// you can staple URLs onto attributed strings
let attrString = NSMutableAttributedString(string: nsText as String, attributes:attrs)
// tag each word if it has a hashtag
for word in words {
// found a word that is prepended by a hashtag!
// homework for you: implement #mentions here too.
if word.hasPrefix("#") {
// a range is the character position, followed by how many characters are in the word.
// we need this because we staple the "href" to this range.
let matchRange:NSRange = nsText.rangeOfString(word as String)
// convert the word from NSString to String
// this allows us to call "dropFirst" to remove the hashtag
var stringifiedWord:String = word as String
// drop the hashtag
stringifiedWord = String(stringifiedWord.characters.dropFirst())
// check to see if the hashtag has numbers.
// ribl is "#1" shouldn't be considered a hashtag.
let digits = NSCharacterSet.decimalDigitCharacterSet()
if let numbersExist = stringifiedWord.rangeOfCharacterFromSet(digits) {
// hashtag contains a number, like "#1"
// so don't make it clickable
} else {
// set a link for when the user clicks on this word.
// it's not enough to use the word "hash", but you need the url scheme syntax "hash://"
// note: since it's a URL now, the color is set to the project's tint color
attrString.addAttribute(NSLinkAttributeName, value: "hash:\(stringifiedWord)", range: matchRange)
}
}
}
// we're used to textView.text
// but here we use textView.attributedText
// again, this will also wipe out any fonts and colors from the storyboard,
// so remember to re-add them in the attrs dictionary above
self.attributedText = attrString
}
}
To use this you can do something like this:
self.textView.text = "This is an #example test"
self.textView.resolveHashTags()
Updated for Swift 4.0:
extension UITextView {
func resolveHashTags() {
// turn string in to NSString
let nsText = NSString(string: self.text)
// this needs to be an array of NSString. String does not work.
let words = nsText.components(separatedBy: CharacterSet(charactersIn: "#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_").inverted)
// you can staple URLs onto attributed strings
let attrString = NSMutableAttributedString()
attrString.setAttributedString(self.attributedText)
// tag each word if it has a hashtag
for word in words {
if word.count < 3 {
continue
}
// found a word that is prepended by a hashtag!
// homework for you: implement #mentions here too.
if word.hasPrefix("#") {
// a range is the character position, followed by how many characters are in the word.
// we need this because we staple the "href" to this range.
let matchRange:NSRange = nsText.range(of: word as String)
// drop the hashtag
let stringifiedWord = word.dropFirst()
if let firstChar = stringifiedWord.unicodeScalars.first, NSCharacterSet.decimalDigits.contains(firstChar) {
// hashtag contains a number, like "#1"
// so don't make it clickable
} else {
// set a link for when the user clicks on this word.
// it's not enough to use the word "hash", but you need the url scheme syntax "hash://"
// note: since it's a URL now, the color is set to the project's tint color
attrString.addAttribute(NSAttributedStringKey.link, value: "hash:\(stringifiedWord)", range: matchRange)
}
}
}
// we're used to textView.text
// but here we use textView.attributedText
// again, this will also wipe out any fonts and colors from the storyboard,
// so remember to re-add them in the attrs dictionary above
self.attributedText = attrString
}
}
One option would be to use an NSAttributedString, something like this...
func convertHashtags(text:String) -> NSAttributedString {
let attrString = NSMutableAttributedString(string: text)
attrString.beginEditing()
// match all hashtags
do {
// Find all the hashtags in our string
let regex = try NSRegularExpression(pattern: "(?:\\s|^)(#(?:[a-zA-Z].*?|\\d+[a-zA-Z]+.*?))\\b", options: NSRegularExpressionOptions.AnchorsMatchLines)
let results = regex.matchesInString(text,
options: NSMatchingOptions.WithoutAnchoringBounds, range: NSMakeRange(0, text.characters.count))
let array = results.map { (text as NSString).substringWithRange($0.range) }
for hashtag in array {
// get range of the hashtag in the main string
let range = (attrString.string as NSString).rangeOfString(hashtag)
// add a colour to the hashtag
attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)
}
attrString.endEditing()
}
catch {
attrString.endEditing()
}
return attrString
}
Then assign your attributedText like this...
let myText = "some text with a #hashtag in side of it #itsnoteasy"
self.textView.attributedText = convertHashtags(myText)
For swift 4.0
extension UITextView {
func resolveHashTags() {
// turn string in to NSString
let nsText = NSString(string: self.text)
// this needs to be an array of NSString. String does not work.
let words = nsText.components(separatedBy: CharacterSet(charactersIn: "#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_").inverted)
// you can staple URLs onto attributed strings
let attrString = NSMutableAttributedString()
attrString.setAttributedString(self.attributedText)
// tag each word if it has a hashtag
for word in words {
if word.count < 3 {
continue
}
// found a word that is prepended by a hashtag!
// homework for you: implement #mentions here too.
if word.hasPrefix("#") {
// a range is the character position, followed by how many characters are in the word.
// we need this because we staple the "href" to this range.
let matchRange:NSRange = nsText.range(of: word as String)
// drop the hashtag
let stringifiedWord = word.dropFirst()
if let firstChar = stringifiedWord.unicodeScalars.first, NSCharacterSet.decimalDigits.contains(firstChar) {
// hashtag contains a number, like "#1"
// so don't make it clickable
} else {
// set a link for when the user clicks on this word.
// it's not enough to use the word "hash", but you need the url scheme syntax "hash://"
// note: since it's a URL now, the color is set to the project's tint color
attrString.addAttribute(NSAttributedStringKey.link, value: "hash:\(stringifiedWord)", range: matchRange)
}
}
}
// we're used to textView.text
// but here we use textView.attributedText
// again, this will also wipe out any fonts and colors from the storyboard,
// so remember to re-add them in the attrs dictionary above
self.attributedText = attrString
}
}
For Swift 3 +
extension UITextView {
func convertHashtags(text:String) -> NSAttributedString {
let attr = [
NSFontAttributeName : UIFont.systemFont(ofSize: 17.0),
NSForegroundColorAttributeName : clr_golden,
NSLinkAttributeName : "https://Laitkor.com"
] as [String : Any]
let attrString = NSMutableAttributedString(string: text)
attrString.beginEditing()
// match all hashtags
do {
// Find all the hashtags in our string
let regex = try NSRegularExpression(pattern: "(?:\\s|^)(#(?:[a-zA-Z].*?|\\d+[a-zA-Z]+.*?))\\b", options: NSRegularExpression.Options.anchorsMatchLines)
let results = regex.matches(in: text,
options: NSRegularExpression.MatchingOptions.withoutAnchoringBounds, range: NSMakeRange(0, text.characters.count))
let array = results.map { (text as NSString).substring(with: $0.range) }
for hashtag in array {
// get range of the hashtag in the main string
let range = (attrString.string as NSString).range(of: hashtag)
// add a colour to the hashtag
//attrString.addAttribute(NSForegroundColorAttributeName, value: clr_golden , range: range)
attrString.addAttributes(attr, range: range)
}
attrString.endEditing()
}
catch {
attrString.endEditing()
}
return attrString
}
}
Add UITextViewDelegate in your class and Use like this
self.tv_yourTextView.delegate = self
self.tv_yourTextView.attributedText = tv_yourTextView.convertHashtags(text: "This is an #museer test")
delegate funtion
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
print("hastag Selected!")
return true
}
-> Modified #Wez Answer
when to make mention or hashtag or any word, yo can make it by:
func convertRegex(text:String, regex: String) -> NSAttributedString {
let attr:[NSAttributedString.Key:Any] = [
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 17.0),
NSAttributedString.Key.foregroundColor : UIColor.green,
] as [NSAttributedString.Key : Any]
let attrString = NSMutableAttributedString(string: text)
attrString.beginEditing()
do {
// Find all the specific word in our string
let regex = try NSRegularExpression(pattern: "\\s\(regex)\\b" , options: NSRegularExpression.Options.anchorsMatchLines)
let results = regex.matches(in: text,
options: NSRegularExpression.MatchingOptions.withoutAnchoringBounds, range: NSMakeRange(0, text.count))
let array = results.map { (text as NSString).substring(with: $0.range) }
for word in array {
let range = (attrString.string as NSString).range(of: word)
attrString.addAttributes(attr, range: range)
}
attrString.endEditing()
}
catch {
attrString.endEditing()
}
return attrString
}

Resources