Color attribute is ignored in NSAttributedString with NSLinkAttributeName
Apple Developer has answered:
Please know that our engineering team has determined that this issue behaves as intended based on the information provided.
And they explain why it worked before but doesn't anymore:
Unfortunately, the previous behavior (attributed string ranges with NSLinkAttributeName rendering in a custom color) was not explicitly supported. It happened to work because NSTextField was only rendering the link when the field editor was present; without the field editor, we fall back to the color specified by NSForegroundColorAttributeName.
Version 10.12 updated NSLayoutManager and NSTextField to render links using the default link appearance, similar to iOS. (see AppKit release notes for 10.12.)
To promote consistency, the intended behavior is for ranges that represent links (specified via NSLinkAttributeName) to be drawn using the default link appearance. So the current behavior is the expected behavior.
(emphasis mine)
Customize color for NSLinkAttributeName in UILabel
I also had same issue when I tried to customize UILabel, and I figured, that NSLinkAttributeName
has bigger priority than NSForegroundColorAttributeName
. Or, maybe, NSLinkAttributeName
processed after foreground color.
I ended with cycle through all NSLinkAttributeName
and replace it with my custom attribute with name CustomLinkAttribute
. After that it works like a charm. And I was also able to get link, by accessing to my custom attribute
func setupHtmlLinkTextStyle(attributedString: NSAttributedString) -> NSAttributedString {
let updatedString = NSMutableAttributedString(attributedString: attributedString)
attributedString.enumerateAttribute(NSLinkAttributeName,
in: NSRange(location: 0, length: attributedString.length),
options: [],
using:
{(attribute, range, stop) in
if attribute != nil {
var attributes = updatedString.attributes(at: range.location, longestEffectiveRange: nil, in: range)
attributes[NSForegroundColorAttributeName] = UIColor.green
attributes[NSUnderlineColorAttributeName] = UIColor.green
attributes[NSStrokeColorAttributeName] = UIColor.green
attributes["CustomLinkAttribute"] = attribute!
attributes.removeValue(forKey: NSLinkAttributeName)
updatedString.setAttributes(attributes, range: range)
}
})
return updatedString
}
Restore the visual state of an NSAttributedString after having clicked on it
When the link is clicked, the text is displayed by the field editor. The default link text style in the field editor is blue and underlined.
Solution 1: change the text style of the link in an override of setUpFieldEditorAttributes:
in a subclass of NSTextFieldCell
.
- (NSText *)setUpFieldEditorAttributes:(NSText *)textObj {
NSText *fieldEditor = [super setUpFieldEditorAttributes:textObj];
if ([fieldEditor isKindOfClass:[NSTextView class]]) {
NSMutableDictionary *linkAttributes = [((NSTextView *)fieldEditor).linkTextAttributes mutableCopy];
linkAttributes[NSForegroundColorAttributeName] = [NSColor orangeColor];
[linkAttributes removeObjectForKey:NSUnderlineStyleAttributeName];
((NSTextView *)fieldEditor).linkTextAttributes = linkAttributes;
}
return fieldEditor;
}
Side effect: the field editor is shared by all controls in the window and all controls will now show orange links.
Solution 2: substitute your own field editor by using the fieldEditor:forObject:
method or the windowWillReturnFieldEditor:toObject:
delegate method of NSWindow
. The text field has its own field editor and other controls won't have orange links. No subclasses of NSTextField
or NSTextFieldCell
required.
Example: (AppDelegate is the delegate of the window)
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *textField;
@property (nonatomic, strong) NSTextView *linkFieldEditor;
@end
@implementation AppDelegate
- (NSTextView *)linkFieldEditor {
if (!_linkFieldEditor) {
_linkFieldEditor = [[NSTextView alloc] initWithFrame:NSZeroRect];
_linkFieldEditor.fieldEditor = YES;
NSMutableDictionary *linkAttributes = [_linkFieldEditor.linkTextAttributes mutableCopy];
linkAttributes[NSForegroundColorAttributeName] = [NSColor orangeColor];
[linkAttributes removeObjectForKey:NSUnderlineStyleAttributeName];
_linkFieldEditor.linkTextAttributes = linkAttributes;
}
return _linkFieldEditor;
}
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client {
if (client == self.textField)
return self.linkFieldEditor;
else
return nil;
}
Solution 3: create a subclass of NSTextFieldCell
, implement fieldEditorForView:
and return your own field editor. This is similar to solution 2 but implemented by the cell instead of the window delegate.
Documentation on the field editor: Text Fields, Text Views, and the Field Editor and Using a Custom Field Editor.
Change the color of a link in an NSMutableAttributedString
Swift
Updated for Swift 4.2
Use linkTextAttributes
with a UITextView
textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.green]
And in context:
let attributedString = NSMutableAttributedString(string: "The site is www.google.com.")
let linkRange = (attributedString.string as NSString).range(of: "www.google.com")
attributedString.addAttribute(NSAttributedString.Key.link, value: "https://www.google.com", range: linkRange)
let linkAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: UIColor.green,
NSAttributedString.Key.underlineColor: UIColor.lightGray,
NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue
]
// textView is a UITextView
textView.linkTextAttributes = linkAttributes
textView.attributedText = attributedString
Objective-C
Use linkTextAttributes
with a UITextView
textView.linkTextAttributes = @{NSForegroundColorAttributeName:[UIColor greenColor]};
Source: this answer
And from this post:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"This is an example by @marcelofabri_"];
[attributedString addAttribute:NSLinkAttributeName
value:@"username://marcelofabri_"
range:[[attributedString string] rangeOfString:@"@marcelofabri_"]];
NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor greenColor],
NSUnderlineColorAttributeName: [UIColor lightGrayColor],
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)};
// assume that textView is a UITextView previously created (either by code or Interface Builder)
textView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;
textView.delegate = self;
How to add a link using NSMutableAttributedString that is not underlined?
Try this
EDITED
let mutableString = NSMutableAttributedString(string: "This is a string. This is the link that should be underlined")
mutableString.addAttribute(NSLinkAttributeName, value: "www.website.com", range: NSMakeRange(0, 16))
mutableString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleNone.rawValue, range: NSMakeRange(0, 16))
mutableString.addAttribute(NSUnderlineColorAttributeName, value: UIColor.clearColor(), range: NSMakeRange(0, 16))
I hope this helps you, for me works like charm
Swift 5.5 AttributedString doesn't show in interface
By default, Swift thinks you're applying the SwiftUI attributes, which UIKit doesn't understand. You have to specify what kind of attributed string attribute this is:
attrib[range].uiKit.foregroundColor = .red
// ^^^^^
Related Topics
Adding 3D Object to Argeoanchor
Take a Snapshot of Current Screen with Metal in Swift
Accessing Appstate in Appdelegate with Swiftui's New iOS 14 Life Cycle
Identify Face of a Cube Hit on Touches Began in Swift - Scenekit
Compile Error in Swift 4 on Parameter Passing
Iboutlet and Ibaction in Swift
How to Use an Nsattributedstring with a Scrollview in Swiftui
Select() from Linq in Swift 3.0
Urlsession.Shared.Datataskpublisher Not Working on iOS 13.3
Cllocationcoordinate2D Can't Be Instantiated
In Swift 3, What Is a Way to Compare Two Closures
Swift: Print Decimal Precision of Division
In Xcode 6.1. 'Uiimage' Does Not Have a Member Named 'Size' Error
How to Stop Timer in Text View
How to Add Material to Modelentity Programatically in Realitykit