NSAttributedStringを使ってみる

NSAttributedStringを使うと文字列を装飾して描画することができます。

使いたい属性をNSDictionaryに設定して、NSAttributedStringのインスタンスを生成することで属性付きの文字列を使うことができます。

後から属性を追加したり変更する場合は、NSMutableAttributedStringの方を使います。

 

NSAttributedString UIKit Additions Referenceを見るとiPhoneで使える属性として以下のようなものがあるようです。

 


NSString *const NSFontAttributeName;                             // フォント名 
NSString *const NSParagraphStyleAttributeName;           // 段落の書式
NSString *const NSForegroundColorAttributeName;        // 文字色
NSString *const NSBackgroundColorAttributeName;        // 背景色
NSString *const NSLigatureAttributeName;                       // リガチャ
NSString *const NSKernAttributeName;                             // カーニング
NSString *const NSStrikethroughStyleAttributeName;     // 取り消し線
NSString *const NSUnderlineStyleAttributeName;            // 下線
NSString *const NSStrokeColorAttributeName;                // 枠線の色
NSString *const NSStrokeWidthAttributeName;                // 枠線の幅
NSString *const NSShadowAttributeName;                       // 影
NSString *const NSVerticalGlyphFormAttributeName;      // 縦書き

 

一通り試してみます。

フォント名


NSString *text = @"国境の長いトンネルを抜けると雪国であった。";
UIFont *font = [UIFont fontWithName:@"HiraKakuProN-W6" size:20.f];
NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSFontAttributeName:font}];
[str drawInRect:CGRectMake(0, 0, 200, 100)];
fontname.png

指定した幅に収まらない場合は自動的に折り返されています。

フォントを指定しないと、デフォルトは、Helveticaの12ポイントになるそうです。

 

段落の書式


NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setAlignment:NSTextAlignmentCenter];
NSAttributedString *str = [[NSAttributedString alloc] initWithString:text
                                                          attributes:@{NSParagraphStyleAttributeName:style}];
[str drawInRect:CGRectMake(0, 0, 200, 100)];
centering.png

指定した幅の範囲でセンタリングされました。

段落の書式としては他に、左寄せや右寄せ、改行の種類、1行目や2行目以降のインデント、行間、行の高さ、段落間の空き等の設定ができます。

 

文字が小さいのでフォントも一緒に指定してみます。


NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setAlignment:NSTextAlignmentCenter];
NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSParagraphStyleAttributeName:style,
                                                  NSFontAttributeName:font}];
[str drawInRect:CGRectMake(0, 0, 200, 100)];
centerfont.png

 

文字色


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSForegroundColorAttributeName:[UIColor blueColor],
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
color.png

一行に収まるように必要な描画サイズを取得するようにしました。

 

背景色


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSBackgroundColorAttributeName:[UIColor redColor],
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
background.png

 

リガチャ

リガチャは日本語だと意味が無さそうなので、英語で試してみます。


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:@"Affine"
                           attributes:@{
                           NSFontAttributeName:[UIFont fontWithName:@"Verdana-Bold" size:30.f]}];
[str drawInRect:CGRectMake(0, 100, 400, 100)];
str = [[NSAttributedString alloc]
                           initWithString:@"Affine"
                           attributes:@{NSLigatureAttributeName:@1,
                           NSFontAttributeName:[UIFont fontWithName:@"Verdana-Bold" size:30.f]}];
[str drawInRect:CGRectMake(0, 150, 400, 100)];
ligature.png

上がリガチャ無しで、下がリガチャ有りです。

リガチャを指定すると隣り合ったfとiが繋がって描画されています。

現状、iOSでは、1(デフォルトのリガチャを有効にする)しか使えないみたいです。(OSXでは、2「全てのリガチャを有効にする」も設定可能)

また、何が原因か分りませんが、ビットマップコンテキストへの描画ではリガチャの指定が反映されませんでした。

 

カーニング


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSKernAttributeName:@18.0,
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
kerning.png

文字間の幅が空いていますね。

 

取り消し線


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSStrikethroughStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle],
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
strike.png

 

下線


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle],
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
underline.png

 

枠線


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSStrokeColorAttributeName:[UIColor blueColor],
                           NSStrokeWidthAttributeName:@5.0,
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
stroke.png

NSStrokeColorAttributeNameで色を指定し、NSStrokeWidthAttributeNameで枠線の幅を指定しています。

 


NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowOffset = CGSizeMake(1.f, 1.f);   // 影のサイズ
shadow.shadowColor = [UIColor redColor];      // 影の色
shadow.shadowBlurRadius = 5.f;                // ぼかしの半径
NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSShadowAttributeName:shadow,
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
shadow.png

 

縦書き


NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSVerticalGlyphFormAttributeName:@1,
                           NSFontAttributeName:font}];
CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
vertical.png

ダメですね。どうやらiOSではまだ縦書きの設定はできないようです。ただ、最後の「。」だけ何故か影響を受けてるようです。ん〜なんでだろう。

 

ごちゃ混ぜ

1つの文字列の異なる部分に異なる属性を設定することも出来ます。

    NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:text];
    /* 全体にフォントを適用 */
    [str addAttribute:NSFontAttributeName
                value:[UIFont fontWithName:@"HiraMinProN-W3" size:20.f]
                range:NSMakeRange(0, text.length)];
    /* 一部の範囲に別のフォントを上書きで適用 */
    [str addAttribute:NSFontAttributeName
                value:[UIFont fontWithName:@"STHeitiTC-Medium" size:40.f]
                range:NSMakeRange(3, 6)];
    /* 黄色の文字色 */
    [str addAttribute:NSForegroundColorAttributeName
                value:[UIColor yellowColor]
                range:NSMakeRange(0, 5)];
    /* 打ち消し線 */
    [str addAttribute:NSStrikethroughStyleAttributeName
                value:[NSNumber numberWithInteger:NSUnderlineStyleSingle]
                range:NSMakeRange(10, 3)];
    /* 青の背景色と白の文字色 */
    [str addAttributes:@{NSBackgroundColorAttributeName:[UIColor blueColor],
                                    NSForegroundColorAttributeName:[UIColor whiteColor]}
                 range:NSMakeRange(14, 2)];
    /* 赤の枠線と下線 */
    [str addAttributes:@{NSStrokeColorAttributeName:[UIColor redColor],
NSStrokeWidthAttributeName:@2.0,
NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle]}
                 range:NSMakeRange(17, 3)];

CGSize size = [str size];
[str drawInRect:CGRectMake(0, 0, size.width, size.height)];
mix.png

1つの属性を追加するときは、addAttributeメソッドを、複数の属性を追加する場合は、addAttributesメソッドを使います。

 

NSAttributedStringの比較

NSAttributedStringのisEqualメソッドは、文字列の内容だけでなく、属性の値も比較して同じかどうかを判断します。

NSAttributedString *a = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:20.f]}];
NSAttributedString *b = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:20.f]}];
NSAttributedString *c = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:21.f]}];
NSAttributedString *d = [[NSAttributedString alloc]
                           initWithString:text
                           attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Courier" size:20.f]}];
[a isEqual:b];           // True
[a isEqual:c];           // False
[a isEqual:d];           // False

 

 

UI要素にNSAttributedStringを使う

NSAttributedStringはこの様に直接描画する他に、UILabelやUIButtonのタイトル文字列として設定することもできます。

NSAttributedString *str = [[NSAttributedString alloc]
                           initWithString:@"Push!"
                           attributes:@{NSStrokeColorAttributeName:[UIColor blueColor],
                           NSStrokeWidthAttributeName:@5.f}];
[self.button setAttributedTitle:str forState:UIControlStateNormal];
button.png

 

また、基本的な属性はXcodeのストーリーボード上で直接設定することもできます。

property.png