Is it possible to apply NSAttributedString to CPTTextLayer's Text - objective-c

I want to display a "custom label" for each index of CPTScatterPlot. CPTTextLayer takes the textcolor, font size, etc from textStyle property. I want to display each character of the string which is displayed in the CPTTextLayer with a different color. I know it is possible using NSAttributedString but when I passed this argument to [[CPTTextLayer alloc] initWithText:attributedStr], my application crashed. Is it possible to apply a NSAttributedString to CPTTextLayer's text?

As of version 1.3 CorePlot does allow creating CPTTextLayer based upon NSAttributedString. Here's example:
NSString *smallTextPart = #"Small part ";
NSString *bigTextPart = #"and the bigger one";
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#%#", smallTextPart, bigTextPart]];
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue" size:12.0] range:NSMakeRange(0, smallTextPart.length)];
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue-Bold" size:18.0] range:NSMakeRange(smallTextPart.length, bigTextPart.length)];
CPTTextLayer *txtLayer = [[CPTTextLayer alloc] initWithAttributedText:str];
It also works properly with multi line CPTTextLayer labels (you can split CPTTextLayer into separate lines using '\n' character).
Cheers.

Core Plot currently does not support attributed text. You can add an enhancement request to the Core Plot issue tracker so that this feature is considered for inclusion in a future version.

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;

Objective C label line spacing?

Is there a way to set the distance of two lines within a UILabel?
I tried to do it within Interface Builder but without success.
The code you want will be something like this:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:#"Sample text"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:24];
[attrString addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, strLength)];
uiLabel.attributedText = attrString;
You can use NSAttributedString to add spacing between two lines within a UILabel:
NSString *labelText = #"My String";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:labelText];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:20];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])];
cell.label.attributedText = attributedString ;
OR
If you are using storyboard then you can control line spacing in the storyboard by selecting text type is attributed and add spacing value:
Since iOS 6, Apple added NSAttributedString to UIKit, making it possible to use NSParagraphStyle to change the line spacing.
Alternatively, you can do this via Storyboards using Attributed Text and then clicking the ... symbol. See link below for screenshot.
https://i.stack.imgur.com/aiNfR.png

NSAttributedString with right alignment removes whitespace at the end

I've created a simple chat app where our messages are on the right side (right alignment) and all other messages are on the left side (left alignment). I'm using NSAttributedString because I heavily modify the text with colors etc.
Each message is a UILabel. My problem is that at the end of the message with the right alignment I want to put a whitespace so it looks like this:
"Some example sentence "
and not like this:
"Some example sentece"
and it's removed everytime I put the whitespace there (I also tried with the non-breaking space \u00a0 and I get the same problem (the space is removed)
My code for the right alignment looks like this:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.text /*attributes:attrDict*/];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setAlignment:NSTextAlignmentRight];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attributedString length])];
later I add some other attributes with colors etc. (nothing that changes the text itself). The text is always with the whitespace at the end like this: "Some example sentece "
and at the end I do something like this:
self.attributedText = attributedString;
And... my space is removed. How can I prevent my text from removing the whitespace at the end? I need it there.
EDIT:
if (self.textAlignment == NSTextAlignmentRight) {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setAlignment:NSTextAlignmentRight];
[paragraphStyle setTailIndent:0.1];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attributedString length])];
}
This is my code for the tailIndent and what it does looks like this.
I have a message "test" on the right side of the chat (here it's on the left because I don't know how to right align the text :P)
before tailIndent:
test
after tailIndent:
t
So what happens: The text goes from right to left leaving only the last character in this case. And the tailIndent is only 0.1!
I tried a few values myself, and, contrary to the expectation set by the name of the attribute (and the lack of other guidance in the doc), tailIndent must be negative.
Here's the code (the OP's, basically) without the attribute set:
NSString *text = #"Am I indented?";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setAlignment:NSTextAlignmentRight];
// paragraphStyle.tailIndent = -18.0;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attributedString length])];
self.label.attributedText = attributedString;
Uncomment the line setting tailIndent to a negative value, and you get:
EDIT
Any of the controlling params should be represented as objects, like an NSNumber representing the indent:
NSNumber *theIndent = #(-18);
// then, later:
paragraphStyle.tailIndent = [theIndent intValue];
Only objects, like NSNumbers, may be placed in arrays, dictionaries, core data, etc.

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.

How to make subscripts and superscripts using NSAttributedString?

I need to make subscripts for chemistry formulas (H2O, Na^2+, etc)?
Is this possible to do with NSAttributedString, or is there an alternative/easier way to make subscripts?
Here's what I did in iOS 6. First add the CoreText, and QuartzCore frameworks. Then import:
#import <QuartzCore/QuartzCore.h>
#import <CoreText/CTStringAttributes.h>
#import <CoreText/CoreText.h>
I made a small function that inputs a plain NSString and exports a NSMutableAttributedString with the last character in superscript. This can be modified to allow setting superscript or subscript, change kCTSuperscriptAttributeName value to -1. Also you could add a variable to specify where to put the superscript in the string. Right now it just assumes the end of the string.
- (NSMutableAttributedString *)plainStringToAttributedUnits:(NSString *)string;
{
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:string];
UIFont *font = [UIFont systemFontOfSize:10.0f];
UIFont *smallFont = [UIFont systemFontOfSize:9.0f];
[attString beginEditing];
[attString addAttribute:NSFontAttributeName value:(font) range:NSMakeRange(0, string.length - 2)];
[attString addAttribute:NSFontAttributeName value:(smallFont) range:NSMakeRange(string.length - 1, 1)];
[attString addAttribute:(NSString*)kCTSuperscriptAttributeName value:#"1" range:NSMakeRange(string.length - 1, 1)];
[attString addAttribute:(NSString*)kCTForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, string.length - 1)];
[attString endEditing];
return attString;
}
Now when I want to use it I can do the following to put it in a UITextField:
NSString *qlwUnitsPlainText = #"m3";
self.quantityLoadWeightUnits_textField.attributedText = [self plainStringToAttributedUnits:qlwUnitsPlainText];
I hope this helps somebody else, there's not many examples out there!
This is possible to do with NSAttributedString. The attribute constant you're looking for depends on your platform. For Mac OS X it is NSSuperscriptAttributeName and on iOS it is kCTSuperscriptAttributeName. Pass in a negative value for subscript.
The only caveat is that UILabel on iOS can't draw NSAttributedStrings (yet, fingers crossed for iOS 6). You would need to draw the text using Core Text or find some third party replacement for UILabel that can draw an NSAttributedString.
On iOS, I had missed the kCTSuperscriptAttributeName constant but had good results with font size and "baseline". It gives you a little more control too for less obedient fonts:
+ (NSAttributedString *)attributedStringForText:(NSString *)normalText andSuperscript:(NSString *)superscriptText textSize:(CGFloat)textSize
{
UIFont *normalFont = [Styles mainFontWithSize:textSize];
UIFont *superFont = [Styles mainFontWithSize:textSize / 2];
NSMutableAttributedString *finalStr = [[NSMutableAttributedString alloc] initWithString:normalText attributes:#{NSFontAttributeName: normalFont}];
NSAttributedString *superStr = [[NSAttributedString alloc] initWithString:superscriptText attributes:#{NSFontAttributeName: superFont, NSBaselineOffsetAttributeName:#(textSize/2)}];
[finalStr appendAttributedString:superStr];
return finalStr;
}
For SubScript use value for kCTSuperscriptAttributeName as #-1.
As per the document
#discussion Value must be a CFNumberRef. Default is int value 0. If
supported
by the specified font, a value of 1 enables superscripting and a
value of -1 enables subscripting.
extern const CFStringRef kCTSuperscriptAttributeName
CT_AVAILABLE(10_5, 3_2);
Example- [lblHeader setText:#“Headers [Alpha1 – text”];
NSMutableAttributedString *headerSubscript = [[NSMutableAttributedString alloc]initWithAttributedString: lblHeader.attributedText];
[headerSubscript addAttribute:(NSString *)kCTSuperscriptAttributeName value:#-1 range:NSMakeRange(14,1)];
[lblHeader setAttributedText:headerSubscript];
you can also do the following if you want to make it a litle cleaner
NSDictionary *attr = #{ NSFontAttributeName: smallfont,
(NSString*)kCTSuperscriptAttributeName: #1 }
NSRange fabricWeightRange = NSMakeRange(fabricWeight.location + 2, 1);
[subKeyString setAttributes:attr range:fabricWeightRange];