富文本的基本数据类型是NSAttributedString。**属性化字符串**(attributed string)是把属性设置到某些字符上的字符串。属性可以是任何键值对,但是为了实现富文本,则通常会包含样式信息,比如字体、颜色和缩进。

通常使用NSMutableAttributedString更好,这样我们就可以修改字符串各部分的属性。NSAttributedString则需要字符串的属性保持不变。

下面的例子将创建一个基本的矩形布局来在UITextView中显示一些富文本。相应的工程可以在名为RichText的示例代码中找到。首先,在Interface Builder中添加一个UITextView并且把模式选择为Attributed;然后,创建一个NSAttributedString并设置一些属性。在本例中,我们会创建一个字符串,然后对整个字符串设置字体属性。

ViewController.m(RichText)

    const CGFloat fontSize = 16.0;


    // 创建基本字符串。

    // 注意如何定义一个多行的字符串

    NSString *string =

    @"Here is some simple text that includes bold and italics.n"

    @"n"

    @"We can even include some color.";


    // 创建可变属性化字符串

    NSMutableAttributedString *attrString =

    [[NSMutableAttributedString alloc] initWithString:string];


    NSUInteger length = [string length];


    // 设置基本字体

    UIFont *baseFont = [UIFont systemFontOfSize:fontSize];

    [attrString addAttribute:NSFontAttributeName value:baseFont

                        range:NSMakeRange(0, length)];

正如26.2.1节所讨论的那样,要设置粗体,需要设置不同的字体。对于系统字体来说这很简单,因为请求系统字体的粗体很容易:

   //用系统字体的粗体来设置粗体,搜索单词"bold"

    UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];

    [attrString addAttribute:NSFontAttributeName value:boldFont

                        range:[string rangeOfString:@"bold"]];

但是如果你用的是非系统字体,而又需要粗体或斜体变体呢?不幸的是,UIKit没有很好的办法确定字体的变体,但是Core Text有。链接了CoreText.framework以后就可以用下面的函数了。该函数用UIFont的名字来找到正确的CTFont,然后用CTFontCreateCopyWithSymbolicTraits来添加所请求的变体(比如kCTFontTraitItalic),最后用得到的字体名称来创建正确的UIFont。但愿将来新版本的iOS能让这个过程变得容易一些。

  UIFont * GetVariationOfFontWithTrait(UIFont *baseFont,

                                         CTFontSymbolicTraits trait) {

      CGFloat fontSize = [baseFont pointSize];


      CFStringRef


      baseFontName = (__bridge CFStringRef)[baseFont fontName];

      CTFontRef baseCTFont = CTFontCreateWithName(baseFontName,

                                                  fontSize, NULL);

      CTFontRef ctFont =

      CTFontCreateCopyWithSymbolicTraits(baseCTFont, 0, NULL,

                                         trait, trait);


      NSString *variantFontName =

      CFBridgingRelease(CTFontCopyName(ctFont,

                                       kCTFontPostScriptNameKey));


      UIFont *variantFont = [UIFont fontWithName:variantFontName

                                            size:fontSize];


      CFRelease(ctFont);

      CFRelease(baseCTFont);


      return variantFont;

    }

    ...

    UIFont *italicFont = GetVariationOfFontWithTrait(baseFont,

                                                     kCTFontTraitItalic);

    [attrString addAttribute:NSFontAttributeName value:italicFont

                        range:[string rangeOfString:@"italics"]];

最后,添加合适的属性来加上颜色:

  // 设置颜色

    UIColor *color = [UIColor redColor];

    [attrString addAttribute:NSForegroundColorAttributeName

                        value:color

                        range:[string rangeOfString:@"color"]];

注意这里用了addAttribute:value:range:而不是setAttribute:value:range。这样可以把新属性和已有的属性合并,通常是我们所期望的结果。

设置好所有属性之后,可以给UITextView设置attributedText属性来显示这个字符串:

 self.textView.attributedText = attrString;

大部分具有text属性的控件现在也会有attributedText属性,这样转换已有的代码会容易得多。

有一点很重要,NSAttributedString不是NSString的子类。它包含了一个NSString对象。类似地,NSMutableAttributedString包含了一个NSMutableString对象。尽管属性化字符串也有常用的字符串方法(如length),但通常还得用string或mutalbeString来获取底层的字符串。