Color Attribute Is Ignored in Nsattributedstring with Nslinkattributename

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))

Sample Image

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



Leave a reply



Submit