setting NSAttributed String attribute overrides substring attributes - objective-c

I have created a mutable string which will look like #"testMeIn:greenColor:Different:greencolor:Colors"
NSMutableAttributedString *mutableText = [[NSMutableAttributedString alloc] initWithAttributedString:myString];
UIColor *foregroundColor = [UIColor blackColor];
NSString *key = NSForegroundColorAttributeName;
[mutableText addAttribute:key value:foregroundColor range:NSMakeRange(0, myString.length)];
When I add Attribute foregroundColor , the existing green color in substring gets overridden by the specified black color. Though I can change the code to set the green color for substring, I would like to know is there any other way of applying styles to the part of Strings which doesn't have styles without overriding the existing styles.

You can enumerate over each attribute span in the string, and only change attributes if they are not already set
NSMutableAttributedString* aString =
[[NSMutableAttributedString alloc] initWithString:#"testMeIn DIFFERENT Colors"];
[aString setAttributes:#{NSForegroundColorAttributeName:[UIColor greenColor]}
range:(NSRange){9,9}];
[aString enumerateAttributesInRange:(NSRange){0,aString.length}
options:nil
usingBlock:
^(NSDictionary* attrs, NSRange range, BOOL *stop) {
//unspecific: don't change text color if ANY attributes are set
if ([[attrs allKeys] count]==0)
[aString addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:range];
//specific: don't change text color if text color attribute is already set
if (![[attrs allKeys] containsObject:NSForegroundColorAttributeName])
[aString addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:range];
}];

Related

Setting UILabel with multiple font color at drawatpoint

How to set the multiple font color in UIlabel drawatpoint.
I tried using below code to change the font attribute but I have no idea how to set a NSMutableAttributedString to this since it only accepts NSDictionary
[self.textColor setFill];
[self.text drawAtPoint:rect2.origin withAttributes:attrName];
We use this to set the attribute
NSMutableAttributedString *attrsString =
[[NSMutableAttributedString alloc]
initWithAttributedString:"String1/String2"];
// search for word occurrence
NSRange prange = [lbl.text rangeOfString:#"String1"];
NSRange lrange = [lbl.text rangeOfString:#"String2"];
if (prange.location != NSNotFound) {
[attrsString addAttributes:attributeGreen range:prange];
[attrsString addAttributes:attributeRed range:lrange];
}
lbl.attributedText = attrsString;
Originally we use this in the UILabel subclass - this subclass is used to resize the text.
[self.textColor setFill];
[self.text drawAtPoint:rect2.origin withFont:tmpfont];
I expect to have String1 in green font and String 2 in red font
Add a font attribute with font size.
NSString *string = #"String1/String2";
NSMutableAttributedString *attrsString =
[[NSMutableAttributedString alloc]
initWithAttributedString:#"String1/String2"];
// search for word occurrence
NSRange prange = [lbl.text rangeOfString:#"String1"];
NSRange lrange = [lbl.text rangeOfString:#"String2"];
//Setting font
[attrString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, string.length)];
if (prange.location != NSNotFound) {
[attrsString addAttribute: NSForegroundColorAttributeName value: [UIColor greenColor] range:prange];
}
if (lrange.location != NSNotFound) {
[attrsString addAttribute: NSForegroundColorAttributeName value: [UIColor redColor] range:lrange];
}
lbl.attributedText = attrsString;

how to Replace color in attributed string in objective c

in my attributed string there is multiple colors. like Red,black,green Colors
here is sample string
in this string,I want to replace all red color words into yellow Color.
can anyone please guide me how can i achive this ?
Thank you.
You need to enumerate the NSAttributedString and change the value of the attribute when condition is met.
Text Color attribute is done with NSForegroundColorAttributeName.
attr is the NSMutableAttributedString corresponding to yours.
//Retrieve the current attributedText. You need to make it mutable.
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithAttributedString:yourLabelOrTextView.attributedText];
[attr enumerateAttribute:NSForegroundColorAttributeName
inRange:NSMakeRange(0, [attr length]) options:0
usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
if ([value isKindOfClass:[UIColor class]]) //Check just in case that the value is really a UIColor
{
UIColor *currentColor = (UIColor *)value;
if ([currentColor isEqual:[UIColor redColor]]) //Condition
{
[attr addAttribute:NSForegroundColorAttributeName
value:[UIColor yellowColor]
range:range];
}
}
}];
[yourLabelOrTextView setAttributedText:attr]; //Replace the previous attributedText on UI with the new one.
You could remove the previous color (red) and then apply the new one, but since there is a unicity you don't have to, it will replace it.

NSTextView: format text programmatically

How can I format parts of a text in a NSTextView programmatically? For example, make all occurrences of the word "foo" blue or make all the text grey but the current paragraph (where the cursor is) solid black?
Thanks
You can use NSAttributedString or NSMutableAttributedString just specify text format (color, text size, etc) and pass it to your NSTextView, for example:
NSString *str = #"test string";
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString: str];
NSDictionary *attributes = #{
NSForegroundColorAttributeName : [NSColor redColor],
NSFontAttributeName : [NSFont fontWithName:#"HelveticaNeue-Bold" size:12.0]
};
[attrString setAttributes:attributes range:NSMakeRange(0, str.length)];
[[self.myNSTextView textStorage] appendAttributedString: attrString];
That will set up all your text to be the same but just replace range attribute with the one you want to change only this part of the text:
NSMakeRange(0, 2) this will add just the text attributes to first two lerrers.

NSAttributedString with link

I have string with 2 words. I want to color 2 words with different colors say red and green.
Also it the whole string should have clickable link. I tried with following code, the link attribute overrides the previous colors.
NSString *str = #"xxxx yyyyyy";
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:str];
[attStr addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor] range:NSMakeRange(0, 4)];
[attStr addAttribute:NSForegroundColorAttributeName
value:[UIColor blueColor] range:NSMakeRange(5, str.length-5)];
NSMutableAttributedString *clickStr = [[NSMutableAttributedString alloc] initWithAttributedString:attStr];
[clickStr addAttribute:NSLinkAttributeName value:#"textLink:link" range:NSMakeRange(0, str.length)];
As far as I know, you can't override the link style in a default attributed string. You'll have to use something like TTTAttributedLabel though it does have some bugs on iOS 8 still.

Custom NSFormatter in Objective C

I am trying to write my own custom formatter in Objective C by subclassing NSNumberFormatter. Specifically what I'd like to do is make a number turn red if it is above or below certain values. The apple documentation says
For example, if you want negative financial amounts to appear in red, you have this method return a string with an attribute of red text. In attributedStringForObjectValue:withDefaultAttributes: get the non-attributed string by invoking stringForObjectValue: and then apply the proper attributes to that string.
Based on this advice I implemented the following code
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:[self stringForObjectValue:anObject]];
if ([[attrString string] floatValue] < -20.0f) {
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, 10)];
return attrString;
} else return attrString;
}
But when I test this all it does is freeze my application. Any advice would be appreciated. Thanks.
I believe this has something to do with your NSRange that you create. I believe your length (10 in your example) is out of bounds. Try getting the length of the string that you use to initialize your NSMutableAttributedString.
For example:
- (NSAttributedString*) attributedStringForObjectValue: (id)anObject withDefaultAttributes: (NSDictionary*)attr;
{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < -20.0f)
{
[attrString addAttribute:#"NSForegroundColorAttributeName" value:[NSColor redColor] range:NSMakeRange(0, stringLength)];
}
return attrString;
}
Here is how I was finally able to implement this. To make it more visible when a number is negative, I decided to make the background of the text red with white text. The following code does work in a NSTextField cell. I'm not sure why the code in my question (and the answer) does not work, addAttribute should work.
- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes: (NSDictionary *)attributes{
NSString *string = [self stringForObjectValue:anObject];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
NSInteger stringLength = [string length];
if ([[attrString string] floatValue] < 0)
{
NSDictionary *firstAttributes = #{NSForegroundColorAttributeName: [NSColor whiteColor],
NSBackgroundColorAttributeName: [NSColor blueColor]};
[attrString setAttributes:firstAttributes range:NSMakeRange(0, stringLength)];
}
return attrString;
}