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?
Solution 1:
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!
Solution 2:
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 NSAttributedString
s (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
.
Solution 3:
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;
}