属性字符串顾名思义可以按照开发者的想法设定字符串的属性,和以往的NSString不同的是,它可以根据截取字符串的任意字串进行设置(通过range来控制范围),所以NSAttributeString的引入更加方便我们定义多样的展示样式。
例如:9.8 10分 01天10时20分15秒
林林总总都可以用属性字符串实现。只要是字体的属性都可以可选的设定,包括对字体,字体颜色,字体尺寸等等、、、
当然NSAttributedString也不是万能的,当它无法满足需求的时候,可以使用富文本编译(在之后的博客中,会向大家介绍富文本的基本知识)
以下简单的代码示例摘自他人博客(实在是太懒了, 就简单介绍一下)
首先导入CoreText.framework,并在需要使用的文件中导入:
#import<CoreText/CoreText.h>
创建一个NSMutableAttributedStrin
- NSMutableAttributedStrin
g *attriString = [[[NSMutableAttributedStrin g alloc] initWithString:@"this is test!"] -
autorelease];
- //把this的字体颜色变为红色
- [attriString
addAttribute:(NSString *)kCTForegroundColorAttrib uteName -
value:(id)[UIColor redColor].CGColor -
range:NSMakeRange(0, 4)]; - //把is变为黄色
- [attriString
addAttribute:(NSString *)kCTForegroundColorAttrib uteName -
value:(id)[UIColor yellowColor].CGColor -
range:NSMakeRange(5, 2)]; - //改变this的字体,value必须是一个CTFontRef
- [attriString
addAttribute:(NSString *)kCTFontAttributeName -
value:(id)CTFontCreateWithName((CFStringRef)[UIFont boldSystemFontOfSize:14].fontName, -
14, -
NULL) -
range:NSMakeRange(0, 4)]; - //给this加上下划线,value可以在指定的枚举中选择
- [attriString
addAttribute:(NSString *)kCTUnderlineStyleAttribu teName -
value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] -
range:NSMakeRange(0, 4)]; - return
attriString;
这样就算是配置好了,但是我们可以发现NSAttributedString继承于NSObject,并且不支持任何draw的方法,那我们就只能自己draw了。写一个UIView的子类(假设命名为TView),在initWithFrame中把背景色设为透明(self.backgroundColor= [UIColor clearColor]),然后在重写drawRect方法:
- -(void)drawRect:(CGRect)rect{
-
[super drawRect:rect]; -
-
NSAttributedString *attriString = getAttributedString(); -
-
CGContextRef ctx = UIGraphicsGetCurrentCont ext(); -
CGContextConcatCTM(ctx, CGAffineTransformScale(CGAffineTransformMakeTra nslation(0, rect.size.height), 1.f, -1.f)); -
-
CTFramesetterRef framesetter = CTFramesetterCreateWithA ttributedString((CFAttributedStringRef)attriString); -
CGMutablePathRef path = CGPathCreateMutable(); -
CGPathAddRect(path, NULL, rect); -
-
CTFrameRef frame = CTFramesetterCreateFrame (framesetter, CFRangeMake(0, 0), path, NULL); -
CFRelease(path); -
CFRelease(framesetter); -
-
CTFrameDraw(frame, ctx); -
CFRelease(frame); - }
在代码中我们调整了CTM(current transformation matrix),这是因为Quartz2D的坐标系统不同,比如(10, 10)到(20, 20)的直线坐标:
坐标类似于数学中的坐标,可以先不调整CTM,看它是什么样子的,下面两种调整方法是完全一样的:
- CGContextConcatCTM(ctx,
CGAffineTransformScale(CGAffineTransformMakeTra nslation(0, rect.size.height), 1.f, -1.f));
- CGContextTranslateCTM(ctx,
0, rect.size.height); - CGContextScaleCTM(ctx,
1, -1);
CTFramesetter是CTFrame的创建工厂,NSAttributedString需要通过CTFrame绘制到界面上,得到CTFramesetter后,创建path(绘制路径),然后得到CTFrame,最后通过CTFrameDraw方法绘制到界面上。
如果想要计算NSAttributedString所要的size,就需要用到这个API:
CTFramesetterSuggestFram
设置行间距和换行模式都是设置一个属性:kCTParagraphStyleAttribu
属性,其中就包括
- kCTLineBreakByCharWrappi
ng - kCTParagraphStyleSpecifi
erLineSpacingAdjustment
- //段落
-
//line break - CTParagraphStyleSetting
lineBreakMode; - CTLineBreakMode
lineBreak = kCTLineBreakByCharWrappi ng; //换行模式 - lineBreakMode.spec
= kCTParagraphStyleSpecifi erLineBreakMode; - lineBreakMode.value
= &lineBreak; - lineBreakMode.valueSize
= sizeof(CTLineBreakMode); -
//行间距 - CTParagraphStyleSetting
LineSpacing; - CGFloat
spacing = 4.0; //指定间距 - LineSpacing.spec
= kCTParagraphStyleSpecifi erLineSpacingAdjustment; - LineSpacing.value
= &spacing; - LineSpacing.valueSize
= sizeof(CGFloat); -
- CTParagraphStyleSetting
settings[] = {lineBreakMode,LineSpacing}; - CTParagraphStyleRef
paragraphStyle = CTParagraphStyleCreate(settings, 2); //第二个参数为settings的长度 - [attributedString
addAttribute:(NSString *)kCTParagraphStyleAttribu teName -
value:(id)paragraphStyle -
range:NSMakeRange(0, attributedString.length)];
-----------------------------------------猥琐的分界线-----------------------------------------
这并不是唯一的方法,还有另一种替代方案:
- CATextLayer
*textLayer = [CATextLayer layer]; - textLayer.string
= getAttributedString(); - textLayer.frame
= CGRectMake(0, CGRectGetMaxY(view.frame), 200, 200); - [self.view.layer
addSublayer:textLayer];
-----------------------------------------猥琐的分界线-----------------------------------------
效果图: