博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS之文本处框架CoreText(C语言的框架)
阅读量:4290 次
发布时间:2019-05-27

本文共 9890 字,大约阅读时间需要 32 分钟。

 

我们通过NSAttributedString创建一个CTFramesetter,这时候会自动创建一个 CTTypesetter实例,它负责管理字体,下面通过CTFramesetter来创建一个或多个frame来渲染文字。然后Core Text会根据frame的大小自动创建CTLine(每行对应一个CTLine)和CTRun(相同格式的一个或多个相邻字符组成一个CTRun)。

      举例来说,Core Text将创建一个CTRun来绘制一些红色文字,然后创建一个CTRun来绘制纯文本,然后再创建一个CTRun来绘制加粗文字等等。要注意,你不需要自己创建CTRun,Core Text将根据NSAttributedString的属性来自动创建CTRun。每个CTRun对象对应不同的属性,正因此,你可以自由的控制字体、颜色、字间距等等信息。

  1. (void)drawRect:(CGRect)rect  
  2.  
  3.     [super drawRect:rect];  
  4.     CGContextRef context UIGraphicsGetCurrentContext();  
  5.    
  6.     CGMutablePathRef path CGPathCreateMutable(); //1  
  7.     CGPathAddRect(path, NULL, self.bounds );  
  8.    
  9.     NSAttributedString* attString [[[NSAttributedString alloc]  
  10.         initWithString:@"Hello core text world!"autorelease]; //2  
  11.    
  12.     CTFramesetterRef framesetter  
  13.         CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); //3  
  14.     CTFrameRef frame  
  15.         CTFramesetterCreateFrame(framesetter,  
  16.             CFRangeMake(0, [attString length]), path, NULL);  
  17.    
  18.     CTFrameDraw(frame, context); //4  
  19.    
  20.     CFRelease(frame); //5  
  21.     CFRelease(path);  
  22.     CFRelease(framesetter);  
  23.  

让我们对应注释中的数字解释一下上面的代码:

  1. 我们创建了一个CGPath,来做完绘制文字的区域。Core Text在Mac下支持不同的形状比如矩形、环形,但是在iOS里只支持矩形。在这个示例中,我们用整个屏幕来做完显示区域,所以通过self.bounds来创建一个CGPath。
  2. 在Core Text我们要渲染的文字不是用NSString而是用NSAttributedString。 NSAttributedString是非常强力的类,它允许你对文字设置不同的样式。然而暂时我们还用不到这些,现在仅仅通过纯文本创建一个NSAttributedString。
  3. CTFramesetter是Core Text中非常重要的一个类。 它管理了你的字体和文本渲染块(CTFrame). 暂时你需要知道的是CTFramesetterCreateWithAttributedString 会通过一个NSAttributedString创建一个 CTFramesetter。下面通过刚刚创建的framesetter来创建一个frame, CTFramesetterCreateFrame的参数分别是:一个framesetter、将显示的文字的range(这里我们使用这个文字长度)、文本将要显示的区域(刚刚创建的CGPath).
  4. CTFrameDraw在给定context里面绘制frame。
  5. 最后别忘记清理资源

      你可能注意到了,Core Text提供的都是c形式的api二不是Objective-C对象。许多iOS上系统级别的库为了效率和通用都是用纯c写的。别担心,你会发现Core Text函数用起来都非常简单。最重要的事情是别忘记CFRelease掉所有你Create出来的引用。

================================================

先来了解一下该框架的整体视窗组合图:

CTFrame 作为一个整体的画布(Canvas),其中由行(CTLine)组成,而每行可以分为一个或多个小方块(CTRun)。

注意:你不需要自己创建CTRun,Core Text将根据NSAttributedString的属性来自动创建CTRun。每个CTRun对象对应不同的属性,正因此,你可以自由的控制字体、颜色、字间距等等信息。

通常处理步聚:

1.使用core text就是先有一个要显示的string,然后定义这个string每个部分的样式->attributedString -> 生成 CTFramesetter -> 得到CTFrame -> 绘制(CTFrameDraw)

其中可以更详细的设置换行方式,对齐方式,绘制区域的大小等。
2.绘制只是显示,点击事件就需要一个判断了。
CTFrame 包含了多个CTLine,并且可以得到各个line的其实位置与大小。判断点击处在不在某个line上。CTLine 又可以判断这个点(相对于ctline的坐标)处的文字范围。然后遍历这个string的所有NSTextCheckingResult,根据result的rang判断点击处在不在这个rang上,从而得到点击的链接与位置。

 

字体的基本知识:

 

字体(Font):是一系列字号、样式和磅值相同的字符(例如:10磅黑体Palatino)。现多被视为字样的同义词

字面(Face):是所有字号的磅值和格式的综合

字体集(Font family):是一组相关字体(例如:Franklin family包括Franklin Gothic、Fran-klinHeavy和Franklin Compressed)

磅值(Weight):用于描述字体粗度。典型的磅值,从最粗到最细,有极细、细、book、中等、半粗、粗、较粗、极粗

样式(Style):字形有三种形式:Roman type是直体;oblique type是斜体;utakuc type是斜体兼曲线(比Roman type更像书法体)。

x高度(X height):指小写字母的平均高度(以x为基准)。磅值相同的两字母,x高度越大的字母看起来比x高度小的字母要大

Cap高度(Cap height):与x高度相似。指大写字母的平均高度(以C为基准)

下行字母(Descender):例如在字母q中,基线以下的字母部分叫下伸部分

上行字母(Ascender):x高度以上的部分(比如字母b)叫做上伸部分

基线(Baseline):通常在x、v、b、m下的那条线

描边(Stroke):组成字符的线或曲线。可以加粗或改变字符形状

衬线(Serif):用来使字符更可视的一条水平线。如字母左上角和下部的水平线。

无衬线(Sans Serif):可以让排字员不使用衬线装饰。

方形字(Block):这种字体的笔画使字符看起来比无衬线字更显眼,但还不到常见的衬线字的程度。例如Lubalin Graph就是方形字,这种字看起来好像是木头块刻的一样

手写体脚本(Calligraphic script):是一种仿效手写体的字体。例如Murray Hill或者Fraktur字体

艺术字(Decorative):像绘画般的字体

Pi符号(Pisymbol):非标准的字母数字字符的特殊符号。例如Wingdings和Mathematical Pi

连写(Ligature):是一系列连写字母如fi、fl、ffi或ffl。由于字些字母形状的原因经常被连写,故排字员已习惯将它们连写。

const CFStringRef kCTCharacterShapeAttributeName;              
//字体形状属性  必须是CFNumberRef对象默认为0,非0则对应相应的字符形状定义,如1表示传统字符形状
const CFStringRef kCTFontAttributeName;                        
//字体属性   必须是CTFont对象const CFStringRef kCTKernAttributeName;                        
//字符间隔属性 必须是CFNumberRef对象const CFStringRef kCTLigatureAttributeName;                 
//设置是否使用连字属性,设置为0,表示不使用连字属性。标准的英文连字有FI,FL.默认值为1,既是使用标准连字。也就是当搜索到f时候,会把fl当成一个文字。必须是CFNumberRef 默认为1,可取0,1,2const CFStringRef kCTForegroundColorAttributeName;             
//字体颜色属性  必须是CGColor对象,默认为blackconst CFStringRef kCTForegroundColorFromContextAttributeName; 
//上下文的字体颜色属性 必须为CFBooleanRef 默认为False,const CFStringRef kCTParagraphStyleAttributeName;              
//段落样式属性 必须是CTParagraphStyle对象 默认为NILconst CFStringRef kCTStrokeWidthAttributeName;              
//笔画线条宽度 必须是CFNumberRef对象,默为0.0f,标准为3.0fconst CFStringRef kCTStrokeColorAttributeName;              
//笔画的颜色属性 必须是CGColorRef 对象,默认为前景色const CFStringRef kCTSuperscriptAttributeName;              
//设置字体的上下标属性 必须是CFNumberRef对象 默认为0,可为-1为下标,1为上标,需要字体支持才行。如排列组合的样式Cn1const CFStringRef kCTUnderlineColorAttributeName;           
//字体下划线颜色属性 必须是CGColorRef对象,默认为前景色const CFStringRef kCTUnderlineStyleAttributeName;           
//字体下划线样式属性 必须是CFNumberRef对象,默为kCTUnderlineStyleNone 可以通过CTUnderlineStypleModifiers 进行修改下划线风格const CFStringRef kCTVerticalFormsAttributeName;
//文字的字形方向属性 必须是CFBooleanRef 默认为false,false表示水平方向,true表示竖直方向const CFStringRef kCTGlyphInfoAttributeName;
//字体信息属性 必须是CTGlyphInfo对象const CFStringRef kCTRunDelegateAttributeName
//CTRun 委托属性 必须是CTRunDelegate对象

举例说明:

 

 

  1. NSMutableAttributedString *mabstring = [[NSMutableAttributedString alloc]initWithString:@"This is a test of characterAttribute. 中文字符"];  

 

 

  1. //设置字体属性  
  2.   CTFontRef font = CTFontCreateWithName(CFSTR("Georgia"), 40, NULL);  
  3.   [mabstring addAttribute:(id)kCTFontAttributeName value:(id)font range:NSMakeRange(0, 4)];   
  1. //设置斜体字  
  2.     CTFontRef font = CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName, 14, NULL);  
  3.     [mabstring addAttribute:(id)kCTFontAttributeName value:(id)font range:NSMakeRange(0, 4)];  
  1. //下划线  
  2.     [mabstring addAttribute:(id)kCTUnderlineStyleAttributeName value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] range:NSMakeRange(0, 4)];   
  1. //下划线颜色  
  2.     [mabstring addAttribute:(id)kCTUnderlineColorAttributeName value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 4)];  
  1. //设置字体简隔 eg:test   
  2.     long number = 10;  
  3.     CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);  
  4.     [mabstring addAttribute:(id)kCTKernAttributeName value:(id)num range:NSMakeRange(10, 4)];  

  1. //设置连字  
  2. long number = 1;  
  3.     CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);  
  4.     [mabstring addAttribute:(id)kCTLigatureAttributeName value:(id)num range:NSMakeRange(0, [str length])];  

连字还不会使用,未看到效果。

  1. //设置字体颜色  
  2.     [mabstring addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor redColor].CGColor range:NSMakeRange(0, 9)];  

  1. //设置字体颜色为前影色  
  2.     CFBooleanRef flag = kCFBooleanTrue;  
  3.     [mabstring addAttribute:(id)kCTForegroundColorFromContextAttributeName value:(id)flag range:NSMakeRange(5, 10)];  

无明显效果。

 

 

  1. //设置空心字  
  2.     long number = 2;  
  3.     CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);  
  4.     [mabstring addAttribute:(id)kCTStrokeWidthAttributeName value:(id)num range:NSMakeRange(0, [str length])];  

  1. //设置空心字  
  2.     long number = 2;  
  3.     CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);  
  4.     [mabstring addAttribute:(id)kCTStrokeWidthAttributeName value:(id)num range:NSMakeRange(0, [str length])];  
  5.        
  6.     //设置空心字颜色  
  7.     [mabstring addAttribute:(id)kCTStrokeColorAttributeName value:(id)[UIColor greenColor].CGColor range:NSMakeRange(0, [str length])];  

在设置空心字颜色时,必须先将字体高为空心,否则设置颜色是没有效果的。

 

  1. //对同一段字体进行多属性设置      
  2.     //红色  
  3.     NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)[UIColor redColor].CGColor forKey:(id)kCTForegroundColorAttributeName];  
  4.     //斜体  
  5.     CTFontRef font = CTFontCreateWithName((CFStringRef)[UIFont italicSystemFontOfSize:20].fontName, 40, NULL);  
  6.     [attributes setObject:(id)font forKey:(id)kCTFontAttributeName];  
  7.     //下划线  
  8.     [attributes setObject:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble] forKey:(id)kCTUnderlineStyleAttributeName];  
  9.       
  10.     [mabstring addAttributes:attributes range:NSMakeRange(0, 4)];  

 

- (void)drawRect:(CGRect)rect {

    NSString *str1 =@"This is a test of characterAttribute. 中文字符";

    NSMutableAttributedString *mabstring = [[NSMutableAttributedStringalloc]initWithString:str1];

    UILabel *lbl=[[UILabelalloc]initWithFrame:CGRectMake(20,20, 200, 30)];

    lbl.text=str1;

    

    [self addSubview:lbl];

    [mabstring beginEditing];

    

    long  number = 2;

    CFNumberRef num =CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&number);

    [mabstring addAttribute:(id)kCTStrokeWidthAttributeNamevalue:(__bridgeid _Nonnull)(num)range:NSMakeRange(0, [str1length])];

    

    CTFramesetterRef framesetter =CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mabstring);

    

    CGMutablePathRef Path =CGPathCreateMutable();

    

    CGPathAddRect(Path, NULL ,CGRectMake(10 ,0 ,self.bounds.size.width ,self.bounds.size.height-30));

    

    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0,0), Path, NULL);

    

    CGContextRef context =UIGraphicsGetCurrentContext();

    CTFrameDraw(frame,context);

    

    [mabstring endEditing];

}

  1. (void)drawRect:(CGRect)rect  
  2.  
  3.     [super drawRect:rect];  
  4.     CGContextRef context UIGraphicsGetCurrentContext();  
  5.    
  6.     CGMutablePathRef path CGPathCreateMutable(); //1  
  7.     CGPathAddRect(path, NULL, self.bounds );  
  8.    
  9.     NSAttributedString* attString [[[NSAttributedString alloc]  
  10.         initWithString:@"Hello core text world!"autorelease]; //2  
  11.    
  12.     CTFramesetterRef framesetter  
  13.         CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); //3  
  14.     CTFrameRef frame  
  15.         CTFramesetterCreateFrame(framesetter,  
  16.             CFRangeMake(0, [attString length]), path, NULL);  
  17.    
  18.     CTFrameDraw(frame, context); //4  
  19.    
  20.     CFRelease(frame); //5  
  21.     CFRelease(path);  
  22.     CFRelease(framesetter);  
  23.  

让我们对应注释中的数字解释一下上面的代码:

  1. 我们创建了一个CGPath,来做完绘制文字的区域。Core Text在Mac下支持不同的形状比如矩形、环形,但是在iOS里只支持矩形。在这个示例中,我们用整个屏幕来做完显示区域,所以通过self.bounds来创建一个CGPath。
  2. 在Core Text我们要渲染的文字不是用NSString而是用NSAttributedString。 NSAttributedString是非常强力的类,它允许你对文字设置不同的样式。然而暂时我们还用不到这些,现在仅仅通过纯文本创建一个NSAttributedString。
  3. CTFramesetter是Core Text中非常重要的一个类。 它管理了你的字体和文本渲染块(CTFrame). 暂时你需要知道的是CTFramesetterCreateWithAttributedString 会通过一个NSAttributedString创建一个 CTFramesetter。下面通过刚刚创建的framesetter来创建一个frame, CTFramesetterCreateFrame的参数分别是:一个framesetter、将显示的文字的range(这里我们使用这个文字长度)、文本将要显示的区域(刚刚创建的CGPath).
  4. CTFrameDraw在给定context里面绘制frame。
  5. 最后别忘记清理资源

      你可能注意到了,Core Text提供的都是c形式的api二不是Objective-C对象。许多iOS上系统级别的库为了效率和通用都是用纯c写的。别担心,你会发现Core Text函数用起来都非常简单。最重要的事情是别忘记CFRelease掉所有你Create出来的引用。

你可能感兴趣的文章
一口气说出 6种 延时队列的实现方案,大厂offer稳稳的
查看>>
原来redis这么简单,跟着文章操作一遍你就会了
查看>>
Redis两种持久化机制RDB和AOF详解(面试常问,工作常用)
查看>>
事务隔离级别中的可重复读能防幻读吗?
查看>>
老伙计,关于JDK并发包,这些不为人知的秘密你知道多少?
查看>>
图片的左右切换
查看>>
进级的RecyclerView——LRecyclerView
查看>>
Android 利用Gradle实现app的环境分离
查看>>
Android系统篇之----Binder机制和远程服务调用
查看>>
JavaScript DOM 属性
查看>>
Gradle 实现 Android 多渠道定制化打包
查看>>
Android开源项目及库整理总结
查看>>
Android快速开发系列 10个常用工具类
查看>>
深入理解JSON对象
查看>>
类似新浪微博帖子显示话题、@好友、表情解析等
查看>>
JSP 自动刷新
查看>>
Java应用架构的演化之路
查看>>
看透内存中的数组
查看>>
Android工程打包成jar文件,并且将工程中引用的jar一起打入新的jar文件中
查看>>
JS单例模式在工作中的使用
查看>>