Hyperlink tappable area get disturbed in UITextView - ios

I am using UITextView to show following text:
txtTest.userInteractionEnabled = true;
txtTest.selectable = true
txtTest.dataDetectorTypes = .Link;
txtTest.text = "<p>لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًا</p>رابط خارجي external link"
UITextView link is not tappable on text رابط خارجي external link. Tappable area goes somewhere else in the UITextView. I just figured out it by tapping random locations on UITextView
Don't know is it the bug of UITextView or something is missing from my side. If anyone experienced the same issue and found any solution?

You will have to make your UIViewController confirm to UITextViewDelegate protocol and implement textView(_:shouldInteractWith:in:interaction:). your standard UITextView setup should look something like this, don't forget the delegate and dataDetectorTypes.
txtTest.delegate = self
txtTest.isUserInteractionEnabled = true // default: true
txtTest.isEditable = false // default: true
txtTest.isSelectable = true // default: true
txtTest.dataDetectorTypes = [.link]
UITextViewDelegate method shouldInteractWithURL:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
print("Link Selected!")
return true
}
and instead of using anchor tag use attributedText to detect link in your selected text in swift way.
let targetLink = "https://google.com"
let yourAttributes = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let yourOtherAttributes = [NSForegroundColorAttributeName: UIColor.red, NSFontAttributeName: UIFont.systemFont(ofSize: 25)]
let partOne = NSMutableAttributedString(string: "لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلً ", attributes: yourAttributes)
let partTwo = NSMutableAttributedString(string: " رابط خارجي external link", attributes: yourOtherAttributes)
let text = " رابط خارجي external link"
let str = NSString(string: text)
let theRange = str.range(of: text)
partTwo.addAttribute(NSLinkAttributeName, value: targetLink, range: theRange)
let combination = NSMutableAttributedString()
combination.append(partOne)
combination.append(partTwo)
txtTest.attributedText = combination
if you want to use HTML then you still have to convert it to NSAttributedString. This function will convert all the HTML tags into NSAttributedString.
extension String{
func convertHtml() -> NSAttributedString{
guard let data = data(using: .utf8) else { return NSAttributedString() }
do{
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
}catch{
return NSAttributedString()
}
}
}
then you can use it like so.
let stringValue = "<p>لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًا</p>رابط خارجي external link"
txtTest.attributedText = stringValue.convertHtml()

Related

Keep hyperlink to specific word in UITextView using attributedString

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.

UITextView with Term and Privacy Hyperlink open in different UIViewController

I'm working with a TextView and I wanted to create two different links within a text where the user accepts the terms and conditions and the privacy policy.
Also I need each link to open a different UIViewController.
Can anyone help me with an example to understand how to achieve this?
I need to understand how to create two Hyper links and how to open them in two different ViewControllers
Thank you all for any help you can give me
For example ... I would like to get a TextView similar to this
You can use the following UITextView delegate Method and Attributed string Tested on swift 5.1 :
let attributedString = NSMutableAttributedString(string: "By continueing you agree terms and conditions and the privacy policy")
attributedString.addAttribute(.link, value: "terms://termsofCondition", range: (attributedString.string as NSString).range(of: "terms and conditions"))
attributedString.addAttribute(.link, value: "privacy://privacypolicy", range: (attributedString.string as NSString).range(of: "privacy policy"))
textView.linkTextAttributes = [ NSAttributedString.Key.foregroundColor: UIColor.blue]
textView.attributedText = attributedString
textView.delegate = self
textView.isSelectable = true
textView.isEditable = false
textView.delaysContentTouches = false
textView.isScrollEnabled = false
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.scheme == "terms" {
//push view controller 1
return false
} else if URL.scheme == "privacy"{
// pushViewcontroller 2
return false
}
return true
// let the system open this URL
}
The UITextView call this function if the user taps or longPresses the URL link. Implementation of this method is optional. By default, the UITextview opens those applications which are responsible for handling the URL type and pass them the URL. You can use this method to trigger an alternative action
Set your textView properties like this.
textView.attributedText = "By Continuing, you aggree to terms <a href='http://termsandservicelink'>Terms Of Services</a> and <a href='https://privacypolicylink'>Privacy Policy</a>".convertHtml()
textView.isEditable = false
textView.dataDetectorTypes = [.link]
textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.blue, NSAttributedString.Key.underlineColor: UIColor.clear]
You can handle tap event on your link in this delegate.
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
//Check your url whether it is privacy policy or terms and do accordigly
return true
}
Here is String extension.
extension String{
func convertHtml() -> NSAttributedString{
guard let data = data(using: .utf8) else { return NSAttributedString() }
do{
return try NSAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
}catch{
return NSAttributedString()
}
}
}
This result is reached using NSAttributedString, Using NSAttributedString, we can style the text,
myLabel.text = "By signing up you agree to our Terms & Conditions and Privacy Policy"
let text = (myLabel.text)!
let underlineAttriString = NSMutableAttributedString(string: text)
let range1 = (text as NSString).rangeOfString("Terms & Conditions")
underlineAttriString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: range1)
let range2 = (text as NSString).rangeOfString("Privacy Policy")
underlineAttriString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: range2)
myLabel.attributedText = underlineAttriString
Extend UITapGestureRecognizer to provide a convenient function to detect if a certain range (NSRange) is tapped on in a UILabel.
extension UITapGestureRecognizer {
func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
// Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
let textStorage = NSTextStorage(attributedString: label.attributedText!)
// Configure layoutManager and textStorage
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
// Configure textContainer
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = label.lineBreakMode
textContainer.maximumNumberOfLines = label.numberOfLines
let labelSize = label.bounds.size
textContainer.size = labelSize
// Find the tapped character location and compare it to the specified range
let locationOfTouchInLabel = self.locationInView(label)
let textBoundingBox = layoutManager.usedRectForTextContainer(textContainer)
let textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
let locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
locationOfTouchInLabel.y - textContainerOffset.y);
let indexOfCharacter = layoutManager.characterIndexForPoint(locationOfTouchInTextContainer, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return NSLocationInRange(indexOfCharacter, targetRange)
}
}
UITapGestureRecognizer send action to tapLabel:, and detect using the extension method didTapAttributedTextInLabel:inRange:.
#IBAction func tapLabel(gesture: UITapGestureRecognizer) {
let text = (myLabel.text)!
let termsRange = (text as NSString).rangeOfString("Terms & Conditions")
let privacyRange = (text as NSString).rangeOfString("Privacy Policy")
if gesture.didTapAttributedTextInLabel(myLabel, inRange: termsRange) {
print("Tapped terms")
} else if gesture.didTapAttributedTextInLabel(myLabel, inRange: privacyRange)
{
print("Tapped privacy")
} else {
print("Tapped none")
}
}

How to set custom font with regular and bold font while setting html string to label in swift 4?

I am getting HTML formatted string from API response, so I need to set it to a label while maintaining Custom Font(as of my App) and also applying a style(bold, regular, etc.) to the label.
I have used an extension that enables to convert the HTML string to regular string with newlines etc. but, I was able to set font here, but only one font and it shows in regular font only, so the whole label is in one font, what I want is to set bold font to the bold HTML part and regular to regular HTML part/tag.
extension String {
var htmlToAttributedString: NSAttributedString {
guard let data = data(using: .utf8) else { return NSAttributedString() }
do {
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
return NSAttributedString()
}
}
var htmlToString: String {
return htmlToAttributedString.string
}
}
//set converted html to string here
let whyAttendAttributedText: NSMutableAttributedString = NSMutableAttributedString(attributedString: attendData.whyAttendData?.desc?.htmlToAttributedString ?? NSAttributedString())
//set font here
whyAttendAttributedText.addAttributes([NSMutableAttributedString.Key.font: CommonSettings.shared.getFont(type: .regular, size: descriptionLabel.font.pointSize), NSMutableAttributedString.Key.foregroundColor: UIColor.white], range: NSMakeRange(0, whyAttendAttributedText.length))
I want to set bold and regular to the text, but as I have set only one font I was unable to get the result, is there any way to set the bold and regular font as in HTML string?
This should help :
extension String {
func attributedString(withRegularFont regularFont: UIFont, andBoldFont boldFont: UIFont) -> NSMutableAttributedString {
var attributedString = NSMutableAttributedString()
guard let data = self.data(using: .utf8) else { return NSMutableAttributedString() }
do {
attributedString = try NSMutableAttributedString(data: data,
options: [.documentType: NSAttributedString.DocumentType.html,
.characterEncoding:String.Encoding.utf8.rawValue],
documentAttributes: nil)
let range = NSRange(location: 0, length: attributedString.length)
attributedString.enumerateAttribute(NSAttributedString.Key.font, in: range, options: .longestEffectiveRangeNotRequired) { value, range, _ in
let currentFont: UIFont = value as! UIFont
var replacementFont: UIFont? = nil
if currentFont.fontName.contains("bold") || currentFont.fontName.contains("Bold") {
replacementFont = boldFont
} else {
replacementFont = regularFont
}
let replacementAttribute = [NSAttributedString.Key.font:replacementFont!]
attributedString.addAttributes(replacementAttribute, range: range)
}
} catch let e {
print(e.localizedDescription)
}
return attributedString
}
}
Let's assume your string after parsing HTML string is: "This is your HTML string"
To create an attributed string,
let attrStr = NSMutableAttributedString(string: "This is your HTML string")
Adding UIFont attribute with value as System-Regular,
attrStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .regular), range: NSRange(location: 0, length: attrStr.length))
Whenever adding an attribute to the attributed string, we need to provide the range of string in which we want to reflect the attribute.
Since we need the whole string to have Regular font, so the range is calculated as the whole string length.
Now, adding UIFont attribute with value as System-Bold to a part of the string, let's say we make HTML as bold,
attrStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .bold), range: (attrStr.string as NSString).range(of: "HTML"))
We've calculated the range of HTML word within the whole string.
Similarly, you can add any of the attributes to the string giving the relevant range values.
Output: This is yourHTMLstring
Edit-1:
To calculate the range of <b> to </b> you need to calculate it manually.
Example:
let str = "This <b>is your HTML</b> string"
let range1 = (str as NSString).range(of: "<b>")
let range2 = (str as NSString).range(of: "</b>")
let requiredRange = NSRange(location: range1.location, length: range2.location + range2.length - range1.location)
The above example will work for single instance of <b>/</b> in the string.
Edit-2:
When string includes multiple instances of <b>/</b>:
let htmlStr = "This is an <b>HTML</b> parsed <b>string</b>"
let arr = htmlStr.components(separatedBy: "</b>")
let attrStr = NSMutableAttributedString()
for str in arr {
if !str.isEmpty {
let range1 = (str as NSString).range(of: "<b>")
let requiredRange = NSRange(location: range1.location, length: str.count - range1.location)
let formattedStr = NSMutableAttributedString(string: str)
formattedStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .bold), range: requiredRange)
attrStr.append(formattedStr)
attrStr.append(NSAttributedString.init(string: "</b>", attributes: [.font : UIFont.systemFont(ofSize: 14.0, weight: .bold)]))
}
}
self.label.attributedText = attrStr
Output: This is an<b>HTML</b>parsed<b>string</b>
Applying Bold and other different styles to the text can be done using below method.
extension String {
func attributedString(with style: [NSAttributedString.Key: Any]? = nil,
and highlightedText: String,
with highlightedTextStyle: [NSAttributedString.Key: Any]? = nil) -> NSAttributedString {
let formattedString = NSMutableAttributedString(string: self, attributes: style)
let highlightedTextRange: NSRange = (self as NSString).range(of: highlightedText as String)
formattedString.setAttributes(highlightedTextStyle, range: highlightedTextRange)
return formattedString
}
}
Input: "This is a test message"
Expectd Output: "This is a test message"
This can be achieved as follows.
let sampleInput = "This is a test message"
let boldtext = "test"
let output = sampleInput.attributedString(with: [.font: UIFont.systemFont(ofSize: 12.0, weight: .regular)],
and: boldtext, with: UIFont.systemFont(ofSize: 12.0, weight: .bold))
Different styles can be applied using different attribute keys. Hope this helps.

Swift 3 render textview using NSAttributedString but want change the default font

First wanna say thank you before if this can be solved..so i have textview that get the data with html tag..so i use attributedText and function to render html..it worked..but i need to change the font family..right now by default it "times new roman" i want to change to "Helvetica" any clue? i use the extension for this :
extension Data {
var attributedString: NSAttributedString? {
do {
return try NSAttributedString(data: self, options:[NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
print(error)
}
return nil
}}
extension String {
var data: Data {
return Data(utf8)
}}
then i use it with :
cell.txtview.attributedText = contentText.data.attributedString
it worked but the font default become "times new roman" i need to change it..any idea? i am very appreciate it before..thank you!
enter image description here
I also already try this...see image below
enter image description here
Your attributed string must be like below :
using this link
let data = "vini".data(using: .utf8)
let attributedString = data!.attributedString
let newAttributedString = NSMutableAttributedString(attributedString: (attributedString)!)
newAttributedString.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, (newAttributedString.length)), options: []) { value, range, stop in
guard let currentFont = value as? UIFont else {
return
}
let fontDescriptor = currentFont.fontDescriptor.addingAttributes([UIFontDescriptorFamilyAttribute: "Helvetica"])
if let newFontDescriptor = fontDescriptor.matchingFontDescriptors(withMandatoryKeys: [UIFontDescriptorFamilyAttribute]).first {
let newFont = UIFont(descriptor: newFontDescriptor, size: currentFont.pointSize)
newAttributedString.addAttributes([NSFontAttributeName: newFont], range: range)
}
}
print(newAttributedString)

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
}

Resources