Getting the attribute dictionaries from a NSAttributedString - objective-c

How can I obtain the attributes of an NSAttributedString?
I thought using enumerateAttributesInRange:NSMakeRange(0, str.length) and then saving every attributes in a NSMutableDictionaries but I'd like to know if exists a better way.
EDIT------
My problem is that I have a NSAttributedString and i want to use this function on its attributes...
CTFramesetterSuggestFrameSizeWithConstraints(framesetter,range, __ATTRIBUTES__, size , NULL);

NSDictionary *attributesFromString = [string attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, string.length)];

UITextView *t = [[UITextView alloc] init];
[t setAttributedText:a];
t.typingAttributtes

Related

Calculate size of NSAttributedString from HTML

I am using a UITextView to display an NSAttributedString from some given HTML, which can includes elements such as bold, italicized, lists, marked, super & subscript, etc.
Currently the code below works pretty well for just paragraphs of text, but once I start adding more complicated elements such as lists and line breaks, the sizing is completely off.
// Create the NSMutableAttributedString from given HTML
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = #{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)};
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithData:data options:options
documentAttributes:nil error:nil];
// Max size for the text container (no limit on height)
CGSize bounds = CGSizeMake(320.0, CGFLOAT_MAX);
// Set the font and size for better rendering results
UIFont *font = [UIFont fontWithName:#"Roboto" size:14.0];
NSDictionary *attrFont = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
NSRange range = NSMakeRange(0, str.length);
[str addAttributes:attrFont range:range];
// Calcualte the size of the UITextView based on the above parameters
CGRect rect = [str boundingRectWithSize:bounds options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading| NSStringDrawingUsesDeviceMetrics context:nil];
I've done some searching and found this thread, but after trying what is suggested over there it still doesn't appear to be working, wondering if anyone knows of a better way to do this?
Calculate Height Of NSAttributedString Containing HTML
Ok after much fiddling around I found that the sizes are actually correct, but the UITextView has some padding / insets that cause the overflow. Setting the following on the textView fixed the problem
[self.textView setTextContainerInset:UIEdgeInsetsZero];
self.textView.textContainer.lineFragmentPadding = 0;

How to create an NSarray with NSAttributedStrings but keeping the attributes within the array?

I want to store different strings with different attributes and store all of them in one array and then display the objects in one label but each object with its respective attribute.
Any suggestions?
EDIT: Solution derived from rmaddy's answer
NSDictionary *redAttrs = #{NSForegroundColorAttributeName:[UIColor redColor]};
NSDictionary *greenAttrs = #{NSForegroundColorAttributeName:[UIColor colorWithRed:0.118 green:0.506 blue:0.000 alpha:1.000]};
NSDictionary *orangeAttrs = #{NSForegroundColorAttributeName:[UIColor orangeColor]};
NSString *stringUm = #"Brazil";
NSString *stringDois = #"USA";
NSString *stringTres = #"England";
NSMutableAttributedString *redString = [[NSMutableAttributedString alloc] initWithString:stringUm];
[redString setAttributes:redAttrs range:NSMakeRange(0,4)];
NSMutableAttributedString *greenString = [[NSMutableAttributedString alloc] initWithString:stringDois];
[greenString setAttributes:greenAttrs range:NSMakeRange(0,2)];
NSMutableAttributedString *orangeString = [[NSMutableAttributedString alloc] initWithString:stringTres];
[orangeString setAttributes:orangeAttrs range:NSMakeRange(0,4)];
NSArray *myStrings = [[NSArray alloc] initWithObjects:redString, greenString, orangeString, nil];
NSLog(#"%#", [myStrings description]);
NSMutableAttributedString *result = [[NSMutableAttributedString alloc]init];
NSAttributedString *delimiter = [[NSAttributedString alloc] initWithString: #", "];
for (NSAttributedString *str in myStrings) {
if (result.length) {
[result appendAttributedString:delimiter];
}
[result appendAttributedString:str];
}
_lblUm.attributedText = result;
Your question is very unclear. But based on your comment to gerrytan's answer, your goal is clearer.
If you have an array of NSAttributedString objects, then you can create a single string by appending them all together with an NSMutableAttributedString.
NSArray *myStrings = ... // your array of NSAttributedString objects
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
// Put this delimiter between each string - change as desired
NSAttributedString *delimiter = [[NSAttributedString alloc] initWithString:#", "];
for (NSAttributeString *str in myStrings) {
if (result.length) {
[result appendAttributedString:delimiter];
}
[result appendAttributedString:str];
}
myLabel.attributedText = result;
UILabel only supports one NSAttributedString. I think what you can do is to place multiple UILabel side by side for each string on the array

Removing annotation string from the NSmutableString

I am working on mapView project. My project will take only 5 annotations on the map. Once new annotation will be added, then first annotation will be drop. I am keeping all annotations latitude and longtitude into NSMutableStringArray. Is there any short way to implement this round robin fashion. First in last out.
for example my nsmutable string:
[12.99, 35.97: 35.85,94.53: 45.44,98.91]
How could I delete first object (each string separated by column operator :) from the string to acquire the following:
[35.85,94.53: 45.44,98.91]
Whats wrong with using the NSMutableArray itself. or maybe I didnt understand your question?
NSMutableArray *queue = [[NSMutableArray alloc] init];
if([queue count] >= 5)
[queue addObject: myObject]; // adds at end
else
object = [queue objectAtIndex:5]; // take out the first added object
[queue removeObjectAtIndex:0];
I have got it work, my solution is below:
NSMutableString *absolute=[NSMutableString stringWithString:pinPoints];
NSLog(#"before absolute: %#",absolute);
NSArray *placemarks=[absolute componentsSeparatedByString:#":"];
if([placemarks count]>5)
{
//NSLog(#"%#",[placemarks objectAtIndex:0]);
NSMutableString *string1 = [NSMutableString stringWithString: [placemarks objectAtIndex:0]];
[absolute replaceOccurrencesOfString:string1 withString:#"" options:0 range:NSMakeRange(0,[pinPoints length])];
pinPoints=absolute;
}
NSLog(#"after absolute: %#",absolute);

Is it possible to to have more than one color in the same UILabel

I want more than one font color in the same UILabel. I dont know if it is possible. I dont really think so but maybe some of you out there have a smart solution for it? Maybe something like stringWithFormat. [NSString stringWithFormatAndColor: #"Text with color: %# %#", text, color, text, color]
This image illustrate what I'm trying to accomplish:
You can achieve this with NSAttributedSting. An easy to use drop-in replacement for UILabels with support for attributed strings is TTTAtributedLabel or OHAttributedLabel
In my experience it is easier to work with NSMutableAttributedStrings and build it up step by step.
NSMutableAttributedString *attrStr = [NSMutableAttributedString attributedStringWithString:#""];
NSMutableAttributedString *a = [NSMutableAttributedString attributedStringWithString:#"This is "];
[a setTextColor:aColorObj];
NSMutableAttributedString *b = [NSMutableAttributedString attributedStringWithString:#"only one "];
[b setTextColor:bColorObj];
NSMutableAttributedString *c = [NSMutableAttributedString attributedStringWithString:#"Label"];
[c setTextColor:cColorObj];
[attrStr appendAttributedString:a];
[attrStr appendAttributedString:b];
[attrStr appendAttributedString:c];
OHAttributedLabel *attributedTextLabel = [[OHAttributedLabel] initWithFrame:frame]
[attributedTextLabel setAttributedText:attrStr];

NSMutableDictionary containing UIImageViews...Add mutable copy to an NSMutableArray? Alternative?

I'm trying to build words in arrays by their key value in a dictionary. However, it won't work the way I'd like it to, because I can't "copy" a UIImageView.
It would be PERFECT, if when adding the letter from the dictionary to an array, it gives me a copy instead of the real object. I don't want to make multiple images of the same letter and add it to the dictionary, because then I could no longer call it by key "s" or "a", and I need more than one array to use the same letters at at time.
What can I do?
//How I create the letters
char s = 's';
NSString *key = [NSString stringWithFormat:#"%c", s];
alphabetS = [[UIImageView alloc] init]];
[alphabetS setImage:[UIImage imageNamed:#"s.png"]];
[allTilesDictionary setObject:alphabetS forKey:key];
[alphabetS release];
//How I use the imageviews from the dictionary
NSMutableArray *wordOne = [[NSMutableArray alloc] initWithObjects:[allTilesDictionary objectForKey:#"s"],[allTilesDictionary objectForKey:#"h"],[allTilesDictionary objectForKey:#"o"],[allTilesDictionary objectForKey:#"p"], nil];
EDIT: My solution. It works perfectly.
for (UIImageView *letters in wordOne)
{
newLetter = [[UIImageView alloc] init];
newLetter.image = letters.image;
newLetter.userInteractionEnabled = YES;
//I can now either lay them out wherever I want on the view, or add them to a new array.
}
Your original code, slightly modified:
//How I create the letters
char s = 's';
NSString *key = [NSString stringWithFormat:#"%c", s];
[allTilesDictionary setObject:[UIImage imageNamed:#"s.png"] forKey:key];
//How I use the imageviews from the dictionary
NSMutableArray *wordOne = [[NSMutableArray alloc] initWithObjects:[allTilesDictionary objectForKey:#"s"],[allTilesDictionary objectForKey:#"h"],[allTilesDictionary objectForKey:#"o"],[allTilesDictionary objectForKey:#"p"], nil];
Your use of that code, slightly modified:
for (UIImage *letters in wordOne)
{
newLetter = [[UIImageView alloc] init];
newLetter.image = letters;
newLetter.userInteractionEnabled = YES;
//I can now either lay them out wherever I want on the view, or add them to a new array.
}
No unnecessary UIImageViews created.
for (UIImageView *letters in wordOne)
{
newLetter = [[UIImageView alloc] init];
newLetter.image = letters.image;
newLetter.userInteractionEnabled = YES;
//I can now either lay them out wherever I want on the view, or add them to a new array.
}