Applying Different Attributes for Different Portions of an Nsattributedstring

Applying different attributes for different portions of an NSAttributedstring

Make a mutable copy of the attributed string, and then use either:

-setAttributes:range:

-addAttributes:range:

-addAttribute:value:range:

-removeAttributes:range:

for example, to set a red color for the first four letters:

NSMutableAttributedString *mutAttrStr = [attributedString mutableCopy];
CGColorRef redClr = [UIColor redColor].CGColor;
NSDictionary *newAttributes = [NSDictionary dictionaryWithObject:(id)redClr forKey:(id)kCTForegroundColorAttributeName];
[mutAttrStr addAttributes:newAttributes range:NSMakeRange(0, 4)];

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableAttributedString_Class/Reference/Reference.html

There's no built-in way to draw the background color on iOS. You can create a custom string constant for the attribute, eg "MyBackgroundColorAttributeName", and then you'll have to draw it yourself.

Using multiple styles in one attributed string

Yes, you can

    var attributedText = NSMutableAttributedString()
let str1 = text1
let str2 = " (\(text2) people added)"
let attr1 = [NSAttributedStringKey.foregroundColor: UIColor.blue]
let attr2 = [NSAttributedStringKey.foregroundColor: UIColor.red]
attributedText.append(NSAttributedString(string: str1, attributes: attr1))
attributedText.append(NSAttributedString(string: str2, attributes: attr2))

cell.textLabel?.attributedText = attributedText

Swift 3 NSAttributedString multiple attributes

The main issue is that you are passing an array [attr.. , attr...] rather than one dictionary.

You need to merge the two dictionaries into one

let attributeFontSaySomething : [String : Any] = [NSFontAttributeName : UIFont.systemFont(ofSize: 12.0)]
let attributeColorSaySomething : [String : Any] = [NSForegroundColorAttributeName : UIColor.blue]

var attributes = attributeFontSaySomething
for (key, value) in attributeColorSaySomething {
attributes(value, forKey: key)
}

let attStringSaySomething = NSAttributedString(string: "Say something", attributes: attributes)

However it might be easier to create the dictionary literally:

let attributes : [String : Any] = [NSFontAttributeName : UIFont.systemFont(ofSize: 12.0), NSForegroundColorAttributeName : UIColor.blue]

Apply attributes from one NSAttributedString to another

Use - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange to get the attributes at a specific index (e.g. 0 for the first character in string). Then use this attribute in - (void)setAttributes:(NSDictionary *)attributes range:(NSRange)aRange to set this attributes for all characters in range.

Change attributes of substrings in a NSAttributedString

@Hyperlord's answer will work, but only if there is one occurence of the word "and" in the input string. Anyway, what I would do is use NSString's stringByReplacingOccurrencesOfString: initially to change every "and" to an "AND", then use a little regex to detect matches in attributed string, and apply NSForegroundColorAttributeName at that range. Here's an example:

NSString *initial = @"This is the text and i want to replace something and stuff and stuff";
NSString *text = [initial stringByReplacingOccurrencesOfString:@"and" withString:@"AND"];

NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:text];

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(AND)" options:kNilOptions error:nil];

NSRange range = NSMakeRange(0,text.length);

[regex enumerateMatchesInString:text options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

NSRange subStringRange = [result rangeAtIndex:1];
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:subStringRange];
}];

And finally, just apply the attributed string to your label.

[myLabel setAttributedText:mutableAttributedString];

replace entire text string in NSAttributedString without modifying other attributes

You can use NSMutableAttributedString and just update the string, the attributes won't change.
Example:

NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:@"my string" attributes:@{NSForegroundColorAttributeName: [UIColor blueColor], NSFontAttributeName: [UIFont systemFontOfSize:20]}];

//update the string
[mutableAttributedString.mutableString setString:@"my new string"];

NSAttributedString, change the font overall BUT keep all other attributes?

Since rmaddy's answer did not work for me (f.fontDescriptor.withFace(font.fontName) does not keep traits like bold), here is an updated Swift 4 version that also includes color updating:

extension NSMutableAttributedString {
func setFontFace(font: UIFont, color: UIColor? = nil) {
beginEditing()
self.enumerateAttribute(
.font,
in: NSRange(location: 0, length: self.length)
) { (value, range, stop) in

if let f = value as? UIFont,
let newFontDescriptor = f.fontDescriptor
.withFamily(font.familyName)
.withSymbolicTraits(f.fontDescriptor.symbolicTraits) {

let newFont = UIFont(
descriptor: newFontDescriptor,
size: font.pointSize
)
removeAttribute(.font, range: range)
addAttribute(.font, value: newFont, range: range)
if let color = color {
removeAttribute(
.foregroundColor,
range: range
)
addAttribute(
.foregroundColor,
value: color,
range: range
)
}
}
}
endEditing()
}
}

Or, if your mix-of-attributes does not include font,

then you don't need to remove old font:

let myFont: UIFont = .systemFont(ofSize: UIFont.systemFontSize);

myAttributedText.addAttributes(
[NSAttributedString.Key.font: myFont],
range: NSRange(location: 0, length: myAttributedText.string.count));


Notes

The problem with f.fontDescriptor.withFace(font.fontName) is that it removes symbolic traits like italic, bold or compressed, since it will for some reason override those with default traits of that font face. Why this is so totally eludes me, it might even be an oversight on Apple's part; or it's "not a bug, but a feature", because we get the new font's traits for free.

So what we have to do is create a font descriptor that has the symbolic traits from the original font's font descriptor: .withSymbolicTraits(f.fontDescriptor.symbolicTraits). Props to rmaddy for the initial code on which I iterated.

I've already shipped this in a production app where we parse a HTML string via NSAttributedString.DocumentType.html and then change the font and color via the extension above. No problems so far.

Example of NSAttributedString with two different font sizes?

You would do something like this…

NSMutableAttributedString *hogan = [[NSMutableAttributedString alloc] initWithString:@"Presenting the great... Hulk Hogan!"];
[hogan addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:20.0]
range:NSMakeRange(24, 11)];

This will set the last two words in 20-point text; the rest of the string will use the default value (which I believe is 12 points). The thing that might be confusing about setting the text size is that you have to set the typeface and the size at the same time—each UIFont object encapsulates both of those properties.



Related Topics



Leave a reply



Submit