Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 295 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
UITextView linkTextAttributes font attribute not applied to NSAttributedString

#1
I have an `NSAttributedString` generated from HTML which includes some links. The attributed string is shown in a UITextView. I wish to apply a different font style for the links and am setting `linkTextAttributes` for this. I've added `NSForegroundColorAttributeName`, `NSFontAttributeName` and `NSUnderlineStyleAttributeName`. For some reason the foreground color is applied but the remaining attributes are not.

myTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor(), NSFontAttributeName : textLinkFont, NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleNone.rawValue]

Has anyone else faced this and how do I change the font style for links without having to apply in-line CSS to the original HTML? Thanks.
Reply

#2
Since attributed strings are generally a pain, I find it is better to avoid the range APIs, and to keep things as immutable as possible. Set the attributes when you create the attributed string rather than going back and trying to set a range. This will also help with localization because figuring out ranges for different languages is quite tricky (the sample below does not show localization to keep things illustrative). It makes things cleaner and easier to follow. When all strings are constructed, assemble the whole thing from the pieces.

// build string
let intro = NSAttributedString(string: "I agree that I have read and understood the ")
let terms = NSAttributedString(string: "Terms and Conditions ", attributes: [.link: "https://apple.com" as Any])
let middle = NSAttributedString(string: "and ")
let privacy = NSAttributedString(string: "Privacy Policy. ", attributes: [.link: "https://example.com" as Any])
let ending = NSAttributedString(string: "This application may send me SMS messages.")
let attrStr = NSMutableAttributedString()
attrStr.append(intro)
attrStr.append(terms)
attrStr.append(middle)
attrStr.append(privacy)
attrStr.append(ending)

// set the link color
let linkAttributes: [NSAttributedString.Key: AnyObject] = [.foregroundColor: UIColor(named: "Secondary")!]
textView.linkTextAttributes = linkAttributes
textView.attributedText = attrStr
Reply

#3
**Swift 5** version of Ryan Heitner's awesome answer:

guard let attributedString = textView.attributedText else { return }
guard let linkFont = UIFont(name: "HelveticaNeue-Bold", size: 20.0) else { return }

let newString = NSMutableAttributedString(attributedString: attributedString)
let types: NSTextCheckingResult.CheckingType = [.link, .phoneNumber]

guard let linkDetector = try? NSDataDetector(types: types.rawValue) else { return }
let range = NSRange(location: 0, length: attributedString.length)

linkDetector.enumerateMatches(in: attributedString.string, options: [], range: range, using: { (match: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop) in
if let matchRange = match?.range {
newString.removeAttribute(NSAttributedString.Key.font, range: matchRange)
newString.addAttribute(NSAttributedString.Key.font, value: linkFont, range: matchRange)
}
})

textView.attributedText = newString
Reply

#4
Updated for Swift 4:


let originalText = NSMutableAttributedString(attributedString: textView.attributedText)
var newString = NSMutableAttributedString(attributedString: textView.attributedText)

originalText.enumerateAttributes(in: NSRange(0..<originalText.length), options: .reverse) { (attributes, range, pointer) in
if let _ = attributes[NSAttributedString.Key.link] {
newString.removeAttribute(NSAttributedString.Key.font, range: range)
newString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 30), range: range)
}
}

self.textView.attributedText = newString // updates the text view on the vc
Reply

#5
For some reason postprocessing attributed string with `enumerateAttributesInRange:` do not work for me.

So I used `NSDataDetector` to detect link and `enumerateMatchesInString:options:range:usingBlock:` to put my style for all links in string.
Here is my processing function:

+ (void) postProcessTextViewLinksStyle:(UITextView *) textView {
NSAttributedString *attributedString = textView.attributedText;
NSMutableAttributedString *attributedStringWithItalicLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];

NSError *error = nil;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink
error:&error];

[detector enumerateMatchesInString:[attributedString string]
options:0
range:NSMakeRange(0, [attributedString length])
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
NSRange matchRange = [match range];
NSLog(@"Links style postprocessing. Range (from: %lu, length: %lu )", (unsigned long)matchRange.location, (unsigned long)matchRange.length);
if ([match resultType] == NSTextCheckingTypeLink) {
[attributedStringWithItalicLinks removeAttribute:NSFontAttributeName range:matchRange];
[attributedStringWithItalicLinks addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"YourFont-Italic" size:14.0f] range:matchRange];
}
}];

textView.attributedText = attributedStringWithItalicLinks;
}
Reply

#6
for simple cases: (without horrible HTML use):

let linkTextAttributes : [String : Any] = [
NSForegroundColorAttributeName: UIColor.red,
NSUnderlineColorAttributeName: UIColor.magenta,
NSUnderlineStyleAttributeName: NSUnderlineStyle.patternSolid.rawValue
]

self.infoText.linkTextAttributes = linkTextAttributes
Reply

#7
This is a swift 3 update of answer above from @Arun Ammannaya

guard let font = UIFont.init(name: "Roboto-Regular", size: 15) else {
return
}
let newString = NSMutableAttributedString(attributedString: string)
let range = NSRange(location:0,length: string.length)
string.enumerateAttributes(in: range, options: .reverse, using: { (attributes : [String : Any], range : NSRange, _) -> Void in
if let _ = attributes[NSLinkAttributeName] {
newString.removeAttribute(NSFontAttributeName, range: range)
newString.addAttribute(NSFontAttributeName, value: font, range: range)
}
})
errorTextView.attributedText = newString
errorTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.green, NSUnderlineStyleAttributeName : NSUnderlineStyle.styleSingle.rawValue]



This is a Swift 3 solution to @CTiPKA which I prefer since it avoids HTML

guard let attributedString = errorTextView.attributedText else {
return
}
guard let font = UIFont.init(name: "Roboto-Regular", size: 15) else {
return
}
let newString = NSMutableAttributedString(attributedString: attributedString)

let types: NSTextCheckingResult.CheckingType = [.link, .phoneNumber]

guard let linkDetector = try? NSDataDetector(types: types.rawValue) else { return }
let range = NSRange(location:0,length: attributedString.length)

linkDetector.enumerateMatches(in: attributedString.string, options: [], range: range, using: { (match : NSTextCheckingResult?,
flags : NSRegularExpression.MatchingFlags, stop) in

if let matchRange = match?.range {
newString.removeAttribute(NSFontAttributeName, range: matchRange)
newString.addAttribute(NSFontAttributeName, value: font, range: matchRange)
}
})
errorTextView.attributedText = newString
Reply

#8
Not sure why linkTextAttributes doesn't work for the font name. But we can achieve this by updating the link attributes of the NSAttributedString. Check the code below.

do {
let htmlStringCode = "For more info <a href=\"http://www.samplelink.com/subpage.php?id=8\">Click here</a>"

let string = try NSAttributedString(data: htmlStringCode.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil)

let newString = NSMutableAttributedString(attributedString: string)
string.enumerateAttributesInRange(NSRange.init(location: 0, length: string.length), options: .Reverse) { (attributes : [String : AnyObject], range:NSRange, _) -> Void in
if let _ = attributes[NSLinkAttributeName] {
newString.removeAttribute(NSFontAttributeName, range: range)
newString.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(30), range: range)
}
}
textField.attributedText = newString
textField.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor(), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleNone.rawValue]

}catch {
}


This is the **objective-C** code for this:

NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType};
NSData *data = [html dataUsingEncoding:NSUnicodeStringEncoding allowLossyConversion:NO];

NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
NSMutableAttributedString *attributedStringWithBoldLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];

[attributedString enumerateAttributesInRange:NSMakeRange(0, attributedString.string.length) options:NSAttributedStringEnumerationReverse usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {

if ([attrs objectForKey:NSLinkAttributeName]) {
[attributedStringWithBoldLinks removeAttribute:NSFontAttributeName range:range];
[attributedStringWithBoldLinks addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"YourFont-Bold" size:16.0] range:range];
}
}];

self.linkTextAttributes = @{NSForegroundColorAttributeName : [UIColor redColor]};

self.attributedText = attributedStringWithBoldLinks;


[![Screenshot][1]][1]


[1]:
Reply

#9
There's also an easy way to apply style for the text if you use html - you can just add the style within the html code. Then you wouldn't need to worry about setting attributes for the text. For example:

NSString *html = [NSString stringWithFormat:@"<p style=\"font-family: Your-Font-Name; color: #344052; font-size: 15px\"><a style=\"color: #0A9FD2\" href=\"https://examplelink.com\">%@</a> %@ on %@</p>", name, taskName, timeString];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType};
NSData *data = [html dataUsingEncoding:NSUTF8StringEncoding];

NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through