富文本
iOS6中,Apple给UILabel
和其他UIKit文本视图添加了直接的属性话字符串的支持,应该说这是一个很方便的特性。不过事实上从iOS3.2开始CATextLayer
就已经支持属性化字符串了。这样的话,如果你想要支持耕地版本的iOS系统,CATextLayer
无疑是你向界面中增加富文本的好办法,而且也不用区跟复杂的Core Text打交道,也省了用UIWebView
的麻烦。
让我们编辑一下示例使用到NSAttributedString
.iOS6及以上我们可以用新的NSTextAttributeName
实例来设置我们的字符串属性,但是练习的目的是为了演示在iOS5及以下,所以我们用了Core Text,也就是说你需要把Core Text framework添加到你的项目中。否则编译器是无法识别属性常量的。
用NSAttributedString实现一个富文本标签
`
CATextLayer *textLayer = [CATextLayer layer];
textLayer.frame = self.labelView.bounds;
textLayer.contentsScale = [UIScreen mainScreen].scale;
[self.labelView.layer addSublayer:textLayer];
textLayer.alignmentMode = kCAAlignmentJustified;
textLayer.wrapped = YES;
UIFont *font = [UIFont systemFontOfSize:15];
NSString *text = @"穿梭时间的画面的钟 从反方向 开始移动\
回到当初爱你的时空 停格内容 不忠\
所有回忆对着我进攻 我的伤口 被你拆封\
誓言太沉重泪被纵容 脸上汹涌 失控\
穿梭时间的画面的钟 从反方向 开始移动\
回到当初爱你的时空 停格内容 不忠\
所有回忆对着我进攻";
NSMutableAttributedString *string = nil;
string = [[NSMutableAttributedString alloc] initWithString:text];
CFStringRef fontName = (__bridge CFStringRef)(font.fontName);
CGFloat fontSize = font.pointSize;
CTFontRef fontRef = CTFontCreateWithName(fontName,fontSize,NULL);
NSDictionary *attribs = @{(__bridge id)kCTForegroundColorAttributeName:(__bridge id)[UIColor blackColor].CGColor,(__bridge id)kCTFontAttributeName:(__bridge id)fontRef};
[string setAttributes:attribs range:NSMakeRange(0, [text length])];
attribs = @{
(__bridge id)kCTForegroundColorAttributeName:(__bridge id)[UIColor redColor].CGColor,
(__bridge id)kCTUnderlineStyleAttributeName:@(kCTUnderlineStyleSingle),
(__bridge id)kCTFontAttributeName:(__bridge id)fontRef
};
[string setAttributes:attribs range:NSMakeRange(6, 5)];
CFRelease(fontRef);
textLayer.string = string;
效果如下:
行距何字距
有必要提一下的是,由于绘制的实现机制不同(CoreText和WebKit),用CATextLayer
渲染和用UILabel
渲染出的文本行距和字距也是不尽相同的。
二者的差异程度(由使用的字体和字符决定)总的来说挺小,但是如果你想正确的显示普通标签和CATextLayer
就一定要记住这一点。
UILabel
的替代品
我们已经证实了CATextLayer
比UILabel
有着更好的性能表现,同时还有额外的布局选项并且在iOS5以上支持富文本。但是与一般的标签比较而言会更加繁琐一些。如果我们真的在需求一个UILabel
的可用替代品,最好是能够在Interface Builder上船舰我们的标签,而且尽可能地像一般的视图一样正常的工作。
我们应该继承UILabel
,然后添加一个子图层CATextLayer
并重写显示文本的方法。但是仍然会有由UILabel
的-drawRect
方法创建的空寄宿图。而且由于CALayer
不支持自动缩放和自动布局,子视图并不是主动跟踪视图边界的大小,所以每次视图大小被更改,我们不得不手动更新子图层的边界。
我们真正想要的是一个用CATextLayer
作为宿主图层的UILabel
子类,这样就可以随着视图自动调整大小而且也没有冗余的寄宿图。
每一个UIView
都是寄宿在一个CALayer
的示例上。这个图层是由视图自动创建和管理的,那我们可以用别的图层类型替代它么?一旦被创建,我们就无法替代这个图层了。但是如果我们继承了UIView
,那我们就可以重写+layerClass
方法使得在创建的时候能返回一个不同的图层子类。UIView
会在初始化的时候调用+layerClass
方法,然后用它的返回类型来创建宿主图层。