How to make subscripts and superscripts using NSAttributedString?
Asked Answered
I

5

26

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?

Infeudation answered 18/12, 2011 at 23:37 Comment(0)
M
28

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.

Merrick answered 18/12, 2011 at 23:46 Comment(4)
Thanks. Can you use kCTSuperscriptAttributeName to make superscripts as well?Infeudation
Yes as I stated, a positive value is for superscripts. A negative value for subscripts.Merrick
Sorry, I don't know how I missed that. Thanks again.Infeudation
It should be noted that UILabel supports NSAttributedString via the attributedString property by now. Values of kCTSuperscriptAttributeName can also be decimal values between -1and 1 to change the super/subscripted text position to whatever fits you.Trillium
F
34

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!

Flannelette answered 8/2, 2013 at 16:48 Comment(3)
Can you please take a look at this part of the attributedString: gist.github.com/mladjan/6663691 Doesn't want to render superscript :(Cherida
You should not that NSMakeRange parameters are firstPosition and length (instead of firstPosition and lastPosition). In the example the reader may be mislead.Scavenger
how can i remove itRadome
M
28

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.

Merrick answered 18/12, 2011 at 23:46 Comment(4)
Thanks. Can you use kCTSuperscriptAttributeName to make superscripts as well?Infeudation
Yes as I stated, a positive value is for superscripts. A negative value for subscripts.Merrick
Sorry, I don't know how I missed that. Thanks again.Infeudation
It should be noted that UILabel supports NSAttributedString via the attributedString property by now. Values of kCTSuperscriptAttributeName can also be decimal values between -1and 1 to change the super/subscripted text position to whatever fits you.Trillium
P
9

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;
}       
Phraseograph answered 6/10, 2014 at 8:31 Comment(3)
what is Styles here ?Deceit
@AadilKeshwani Just a static class to centralise fonts, sizes, colours, and other styles related to the app.Phraseograph
@AadilKeshwani Styles is just a static class acting as a stylesheet, centralising most of the style constants in the app.Phraseograph
S
1

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];
Sidon answered 27/8, 2015 at 6:30 Comment(1)
@Bhargav Rao It is in swift, thats why i've wrote this answer.Glengarry
H
0

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];
Hemipterous answered 6/11, 2013 at 23:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.