CFAttributedString replace occurrences of string? - iphone

I know that in a CFAttributedString does not respond to any method like the stringByReplacingOccurrencesOfString:withString: method of NSString, and I cannot find a method that can do that using a CF(Mutable)AttributedString.
I want to replace some text in the string with the same text but another color, e. g., I have the string #"This is a text" and I want to change the color of the word "text".
I hope the question is clear enough, if it isn't, ask me.
Thanks.

I would add a category on NSMutableAttributedString:
#implementation NSMutableAttributedString (MySearchAndReplaceCategory)
- (void)setAttributes:(NSDictionary *)attributes forOccurencesOfString:(NSString *)target
{
NSRange searchRange = NSMakeRange(0, self.length);
while ( searchRange.length )
{
NSRange range = [self.string rangeOfString:target options:0 range:searchRange];
if ( ! range.length )
break;
[self setAttributes:attributes range:range];
searchRange.length = NSMaxRange(searchRange) - NSMaxRange(range);
searchRange.location = NSMaxRange(range);
}
}
#end
Then use something like that:
UIColor *color = [UIColor greenColor];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:(__bridge id) color.CGColor
forKey:(__bridge id) kCTForegroundColorAttributeName];
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:#"This is a text"];
[text setAttributes:attributes forOccurencesOfString:#"text"];

re: Toll-Free Bridging
CFAtttributeString and NSAttributeString have different attributes keys.
Ex. Color Mac OS X:
NSForegroundColorAttributeName - NSColor - Default blackColor
kCTForegroundColorAttributeName - The value associated with this attribute must be a CGColor object. Default value is black.

Related

UILabel is not displaying its correct value even if it is giving the newly assigned value in console

I have a UILabel which is displayed as a question. Its successfully displaying the question text which has been assigned to it programmatically. But later according to one if else condition, I have to change text in the label.Specifically I want to display an asterik(*) mark at the end of the string if that is a mandatory question.The * should be in red color and rest of the text should be in black.But it displays only the question not the * mark.If I try to print the questLabel.text it is giving the question with * mark at the end.Here is the code that I am trying
questText = questLabel.text;
questText = [questText stringByAppendingString:#"✶"];
NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:questText];
NSMutableAttributedString *text =
[[NSMutableAttributedString alloc]
initWithAttributedString: str];
int length = (int)text.length;
[text addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(length-1, 1)];
[questLabel setAttributedText: text];
If I try to print the value of questLabel.attributedText :
Question{
}✶{
NSColor = "UIDeviceRGBColorSpace 1 0 0 1";
}
And the value for questLabel.text is :Question✶
Please help me out with this..Thanks in advance..
You should change your code to this.
NSString *questText = questLabel.text;
questText = [questText stringByAppendingString:#"✶"];
NSMutableAttributedString *text =
[[NSMutableAttributedString alloc] initWithString:questText];
int length = (int)text.length;
[text addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, length-1)];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(length-1, 1)];
[questLabel setAttributedText: text];
You can also try this
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:self.questLabel.text attributes:#{NSForegroundColorAttributeName:[UIColor blackColor]}];
NSMutableAttributedString *starString = [[NSMutableAttributedString alloc] initWithString:#"✶" attributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
[string appendAttributedString:starString];
[self.questLabel setAttributedText:string];

Color String in the Label

If I want to create some strings having format as these:
the string is the text property of a label.
some characters in this string have color different from other characters.
some characters are underlined and have a link, and when I hit the characters, and other views pop up.
Could somebody tell me how can I realize this effect?
If you support iOS < 6, better use 3rd party component e.g. TTTAttributedLabel. Else use attributedText property of UILabel.
NSDictionary *colors = [[NSDictionary alloc] initWithObjectsAndKeys: [UIColor blueColor], #"Hyd", [UIColor brownColor], #"Bang", [UIColor orangeColor], #"Delhi", [UIColor yellowColor], #"Gujarat", nil];
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:#""];
for (NSString *word in colors) {
UIColor *color = [colors objectForKey:word];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:color forKey:NSForegroundColorAttributeName];
NSAttributedString *substring = [[NSAttributedString alloc] initWithString:word attributes:attributes];
[attributeString appendAttributedString:substring];
}

Make the specific string Pattern bold and blue in UILable

i have a program in which i get a tweets from twitter and show them in UITableviewcell. now problem is that i have to make a all twitter names bold and bule and show them in the orginal tweet with bule and bold names.
For Example i have tweet like this
MT #OraTV: SNEAK PEEK: #tomgreenlive #TheoVon & #DavidBegnaud talk Miley's #twerking #Batfleck &more on
so all the names starting with # should be bold and bule.
i use this code to extract All names starting with # but not know how to bold them and show
them in single uitableviewcell
NSString * aString =twitterMessage
NSMutableArray *substrings = [NSMutableArray new];
NSScanner *scanner = [NSScanner scannerWithString:aString];
[scanner scanUpToString:#"#" intoString:nil];
while(![scanner isAtEnd]) {
NSString *substring = nil;
[scanner scanString:#"#" intoString:nil];
if([scanner scanUpToString:#" " intoString:&substring]) {
[substrings addObject:substring];
}
[scanner scanUpToString:#"#" intoString:nil];
}
you have to build an NSAttributedString by swiping between 2 fonts and colors.
If you're able to detect them, you should probably replace your names by surrounding them with a known markup (eg: #aName). Then, parse the string to build a NSAttributedString.
You can use this code (not tested, you'll probably have to tweak):
// String to parse
NSString *markup = #"MT <color>#OraTV</color>: SNEAK PEEK: <color>#tomgreenlive</color>...";
// Names font and color
UIFont *boldFont = [UIFont boldSystemFontOfSize:15.0f];
UIColor *boldColor = [UIColor blueColor];
// Other text font and color
UIFont *stdFont = [UIFont systemFontOfSize:15.0f];
UIColor *stdColor = [UIColor blackColor];
// Current font and color
UIFont *currentFont = stdFont;
UIColor *currentColor = stdColor;
// Parse HTML string
NSMutableAttributedString *aString = [[NSMutableAttributedString alloc] initWithString:#""];
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:#"(.*?)(<[^>]+>|\\Z)"
options:NSRegularExpressionCaseInsensitive|NSRegularExpressionDotMatchesLineSeparators
error:nil];
NSArray *chunks = [regex matchesInString:markup options:0 range:NSMakeRange(0, [markup length])];
for (NSTextCheckingResult* b in chunks)
{
NSArray *parts = [[markup substringWithRange:b.range] componentsSeparatedByString:#"<"];
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:currentFont,NSFontAttributeName,currentColor,NSForegroundColorAttributeName,nil];
[aString appendAttributedString:[[NSAttributedString alloc] initWithString:[parts objectAtIndex:0] attributes:attrs]];
if([parts count] > 1)
{
NSString *tag = (NSString *)[parts objectAtIndex:1];
if([tag hasPrefix:#"color"])
{
currentFont = boldFont;
currentColor = boldColor;
}
else if([tag hasPrefix:#"/color"])
{
currentFont = stdFont;
currentColor = stdColor;
}
}
}
Hope that helps.
Cyril
So you have all the names properly extracted already? If so, it seems like NSAttributedString is what you want. More information here.
Something like this: [str setTextColor:[UIColor blueColor] range:NSMakeRange(0,5)];
For bold text, use [UIFont boldSystemFontOfSize:fontSize]. See example in the second link above.

Combining Attributed Strings

As an example, say I had an array of 10 NSAttributedStrings, what is the best method for combining them all into one string? I know of the appendAttributedString method, but this only allows for one to be combined at a time, meaning a loop is needed.
Or is there any need to combine them if theyre just going into a textview - just have a loop to add them to that view? Im just trying to get my head around how a lot of text in different formats is added to a textview!
Please, try:
NSRange range = NSMakeRange(0, 1);
NSString *space = #" ";
NSMutableAttributedString *attSpace = [[NSMutableAttributedString alloc] initWithString:space];
[attSpace addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:range];
[attSpace addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue-Light"
size:11.f] range:range];
range = NSMakeRange(0, [string1 length]);
NSMutableAttributedString *att1 = [[NSMutableAttributedString alloc] initWithString:string1];
[att1 addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:range];
[att1 addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue-Light"
size:11.f] range:range];
range = NSMakeRange(0, [string2 length]);
NSMutableAttributedString *att2 = [[NSMutableAttributedString alloc] initWithString:string2];
[att2 addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:range];
[att2 addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue-Light"
size:11.f] range:range];
[att1 appendAttributedString:attSpace];
[att1 appendAttributedString:att2];
I'll share a kind of complex combination I've made mixing plain, striked and bold text in a resultant attributed string over the title of UIButton.
// Monthly button
NSMutableAttributedString *strikedOutPrice = [[NSMutableAttributedString alloc] initWithString:#"6,99"];
[strikedOutPrice setAttributes:#{ NSForegroundColorAttributeName : [UIColor whiteColor], NSStrikethroughStyleAttributeName: #2 } range:NSMakeRange(0, [strikedOutPrice length])];
NSMutableAttributedString *boldPrice = [[NSMutableAttributedString alloc] initWithString:#"4,99"];
[boldPrice setAttributes:#{ NSFontAttributeName:[UIFont boldSystemFontOfSize:16.0f], NSForegroundColorAttributeName : [UIColor whiteColor] } range:NSMakeRange(0, [boldPrice length])];
NSMutableAttributedString* titleStringMonthly = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%# %# %#" , [[LocalizationSystem sharedLocalSystem] localizedStringForKey:#"1 Month for" value:#"1 Mes por"], #"6,99", #"4,99"]];
[titleStringMonthly setAttributes:#{ NSForegroundColorAttributeName : [UIColor whiteColor] } range:NSMakeRange(0, [titleStringMonthly length])];
NSString *language = [Utils getAppLanguage];
if([language isEqualToString:#"es"])
{
[titleStringMonthly replaceCharactersInRange:NSMakeRange(10, 4) withAttributedString:strikedOutPrice];
[titleStringMonthly replaceCharactersInRange:NSMakeRange(15, 4) withAttributedString:boldPrice];
}
else
{
[titleStringMonthly replaceCharactersInRange:NSMakeRange(12, 4) withAttributedString:strikedOutPrice];
[titleStringMonthly replaceCharactersInRange:NSMakeRange(17, 4) withAttributedString:boldPrice];
}
[_oneMonthButton setAttributedTitle:titleStringMonthly forState:UIControlStateNormal];
I imagine that for this case you could have a couple of dynamic counters that keeps track of the index and length of the next range and make the replacements over a NSMutableAttributedString (like I do with my titleStringMonthly on the example)
Hope It helps someone.
You could do something like this
NSString *attr = [NSString stringWithFormat:#"%#%#%#", attributedString1, string2, string3];
Doing so will result in one attr string variable with all 10 of the strings put together, and you could do [textView setText:attr]; :)

Truncate a string and add ellipsis at the end in Objective-c

How to truncate a string in Objective-C and then add the ellipsis at the end?
NSString *origString = #"A very long string blah blah blah";
const int clipLength = 18;
if([origString length]>clipLength)
{
origString = [NSString stringWithFormat:#"%#...",[origString substringToIndex:clipLength]];
}
Use one of these NSString methods to truncate, probably the last:
– substringFromIndex:
– substringWithRange:
– substringToIndex:
and then use the NSString method
– stringByAppendingString:
to add #"..." or whatever ellopsis you like.
For example:
NSString *newString = [[string substringToIndex:12] stringByAppendingString:#"..."];
For your reading pleasure, I recommend the NSString Class Reference.
In case you wish to truncate and add ellipsis to a string with the maximum being a specific width, here is an implementation that takes into account font and size:
+ (NSString *)stringByTruncatingString: (NSString *)string toWidth: (CGFloat)width withFont: (UIFont *)font
{
#define ellipsis #"..."
NSMutableString *truncatedString = [string mutableCopy];
if ([string sizeWithAttributes: #{NSFontAttributeName: font}].width > width) {
width -= [ellipsis sizeWithAttributes: #{NSFontAttributeName: font}].width;
NSRange range = {truncatedString.length - 1, 1};
while ([truncatedString sizeWithAttributes: #{NSFontAttributeName: font}].width > width) {
[truncatedString deleteCharactersInRange:range];
range.location--;
}
[truncatedString replaceCharactersInRange:range withString:ellipsis];
}
return truncatedString;
}
Don't need chuck of code for do this..
the easiest way to do this,
for drawRect
- (void)drawRect:(NSRect)dirtyRect{
NSString *theText = #"bla blah bla bhla bla bla";
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByTruncatingTail];
[theText drawInRect:dirtyRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:style, NSParagraphStyleAttributeName,nil]];
}
hear I use dirtyRect for String's Drawing area you can change it as you wish.
for NSTextField
NSTextField *_warningTF = [[NSTextField alloc]init];
[_warningTF setStringValue:#"sfdsf sdfdsfdsfdsfdsfdsfdsf 1234566789123456789sfdsf dsf dsfdsf"];
[_warningTF.cell setLineBreakMode:NSLineBreakByTruncatingTail];
I wrote simple category to truncate NSString by words:
#interface NSString (TFDString)
- (NSString *)truncateByWordWithLimit:(NSInteger)limit;
#end
#implementation NSString (TFDString)
- (NSString *)truncateByWordWithLimit:(NSInteger)limit {
NSRange r = NSMakeRange(0, self.length);
while (r.length > limit) {
NSRange r0 = [self rangeOfString:#" " options:NSBackwardsSearch range:r];
if (!r0.length) break;
r = NSMakeRange(0, r0.location);
}
if (r.length == self.length) return self;
return [[self substringWithRange:r] stringByAppendingString:#"..."];
}
#end
Usage:
NSString *xx = #"This string is too long, somebody just need to take and truncate it, but by word, please.";
xx = [xx truncateByWordWithLimit:50];
Result:
This string is too long, somebody just need to...
Hope it helps somebody.
the drawWithRect:options:attributes:context method helps. you can try this:
[_text drawWithRect:_textRect options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine attributes:attributes context:nil];