下載地址: https://github.com/RainbowWait/-Label.git
下面就來詳情看看字形的各個參數(shù)也就是所謂的字形度量Glyph Metrics
信息 | 說明 |
---|---|
Origin | 表示位于基線上的焰络、一個字形在排列時基于基線的原點(diǎn) |
Baseline | 表示字形在排列時,字形底部緊靠著的一條直線 |
Line height | 表示一行字形最大高度,等于Ascent 和 Decent(取其絕對值)及 Line gap(leading)三者之和 |
Ascent | 表示上行高度,是基線與字形最高點(diǎn)之間的距離 |
Descent | 表示下行調(diào)試,是基線與字形最低點(diǎn)之間的距離 |
Line gap(leading) | 表示行距,是上方一行的最低點(diǎn)與下方一行的最高點(diǎn)的距離 |
Advancement | 表示簽好兩個字形的原點(diǎn)之間的距離 |
Bounding rectangle | 能夠容納字形的最小矩形形框 |
Italic angle | 斜體字形在垂直方向上沿順時針的傾斜角度 |
X-height | 基線至非突出的小寫字母(如a戴甩、x、e等)最高點(diǎn)的距離 |
Cap height | 基線至大寫字母最高點(diǎn)的距離 |
lineHeight = ascent + |descent| + leading
行高 = 上行高度 + 下行高度的絕對值 + 行間距
二闪彼、坐標(biāo)系
傳統(tǒng)的Mac中的坐標(biāo)系的原點(diǎn)在左下角甜孤,比如NSView默認(rèn)的坐標(biāo)系,原點(diǎn)就在左下角畏腕。但Mac中有些View為了其實(shí)現(xiàn)的便捷將原點(diǎn)變換到左上角缴川,像NSTableView的坐標(biāo)系坐標(biāo)原點(diǎn)就在左上角。
iOS UIKit中描馅,UIView是以左上角為原點(diǎn)把夸,而Core Text一開始的定位是使用與桌面應(yīng)用的排版系統(tǒng),桌面應(yīng)用的坐標(biāo)系是以左下角為原點(diǎn)流昏,即Core Text在繪制的時候也是參照左下角為原點(diǎn)進(jìn)行繪制的扎即,所以需要對當(dāng)前的坐標(biāo)系進(jìn)行處理。
實(shí)際上况凉,Core Graphic 中的context也是以左下角為原點(diǎn)的谚鄙, 但是為什么我們用Core Graphic 繪制一些簡單的圖形的時候不需要對坐標(biāo)系進(jìn)行處理呢,是因?yàn)橥ㄟ^這個方法UIGraphicsGetCurrentContext()來獲得的當(dāng)前context是已經(jīng)被處理過的了刁绒,用下面方法可以查看指定的上下文的當(dāng)前圖形狀態(tài)變換矩陣闷营。
- 方法一
//因?yàn)镃ore Text要配合Core Graphic 配合使用的,如Core Graphic一樣知市,繪圖的時候需要獲得當(dāng)前的上下文進(jìn)行繪制
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(@"當(dāng)前context的變換矩陣 %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
//翻轉(zhuǎn)當(dāng)前的坐標(biāo)系(因?yàn)閷τ诘讓永L制引擎來說傻盟,屏幕左下角為(0,0))
CGContextSetTextMatrix(context, CGAffineTransformIdentity);//設(shè)置字形變換矩陣為CGAffineTransformIdentity嫂丙,也就是說每一個字形都不做圖形變換
CGAffineTransform flipVertical = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height);
CGContextConcatCTM(context, flipVertical);//將當(dāng)前context的坐標(biāo)系進(jìn)行flip
NSLog(@"翻轉(zhuǎn)后context的變換矩陣 %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
- 方法二
//因?yàn)镃ore Text要配合Core Graphic 配合使用的娘赴,如Core Graphic一樣,繪圖的時候需要獲得當(dāng)前的上下文進(jìn)行繪制
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(@"當(dāng)前context的變換矩陣 %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
//翻轉(zhuǎn)當(dāng)前的坐標(biāo)系(因?yàn)閷τ诘讓永L制引擎來說跟啤,屏幕左下角為(0诽表,0))
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
NSLog(@"翻轉(zhuǎn)后context的變換矩陣 %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
CocreText類 | 類說明 |
---|---|
CTFramesetter | 生成CTFrame的類型 |
CTFrame | 文本幀,包含多個CTLine |
CTLine | 一行文本,一行文本包括多個屬性不同的CTRun |
CTRun | 共享相同屬性和方向的連續(xù)字形 |
CTFrame 作為一個整體的畫布(Canvas),其中由行(CTLine)組成隅肥,而每行可以分為一個或多個小方塊(CTRun)
注意:你不需要自己創(chuàng)建CTRun竿奏,Core Text將根據(jù)NSAttributedString的屬性來自動創(chuàng)建CTRun。每個CTRun對象對應(yīng)不同的屬性腥放,正因此泛啸,你可以自由的控制字體、顏色秃症、字間距等等信息
NSAttributedString
CGPathRef path = CGPathCreateWithRect(CGRectMake(0, 0, self.bounds.size.width, UIScreen.mainScreen.bounds.size.height), nil);
NSMutableAttributedString *drawAttributedText1 = [[NSMutableAttributedString alloc] initWithAttributedString:_attributedText];
CTFramesetterRef CTFramesetterCreateWithAttributedString(CFAttributedStringRef string)
CTFramesetter
CTFramesetterRef setter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)drawAttributedText);
-
通過屬性字符串創(chuàng)建CTFramesetterRef對象
CTFramesetterRef CTFramesetterCreateWithAttributedString(CFAttributedStringRef string);
-
CTFramesetterRef對象創(chuàng)建幀對象(CTFrameRef)
CTFrameRef CTFramesetterCreateFrame(CTFramesetterRef framesetter, CFRange stringRange, CGPathRef path, CFDictionaryRef frameAttributes);
-
獲得推薦的文本尺寸大小
CGSize CTFramesetterSuggestFrameSizeWithConstraints(CTFramesetterRef framesetter, CFRange stringRange, CFDictionaryRef frameAttributes, CGSize constraints, CFRange *fitRange);
CTFrameRef
CTFrameRef ctFrame = CTFramesetterCreateFrame(setter, CFRangeMake(0, drawAttributedText.length), path, NULL);
-
通過
CTFrameRef
幀率獲得行數(shù)CTLineRef
對象
CFArrayRef CTFrameGetLines(CTFrameRef frame);
-
通過幀率獲取每行的位置
Origins 傳的是指針 所以該參數(shù)定義成CGPoint origins = [lines.count]
lines
是行數(shù)
void CTFrameGetLineOrigins(CTFrameRef frame, CFRange range, CGPoint *origins);
CTLines
NSArray *lines = (NSArray*)CTFrameGetLines(ctFrame);
-
獲取該行包含的
CTRunRef
CFArrayRef CTLineGetGlyphRuns(CTLineRef line);
-
通過屬性字符串創(chuàng)建
CTLineRef
對象
CTLineRef CTLineCreateWithAttributedString(CFAttributedStringRef attrString)
-
獲取行所在的下標(biāo)位置
CFIndex CTLineGetGlyphCount(CTLineRef line);
-
獲取該行在整個文本幀的位置
CFRange CTLineGetStringRange(CTLineRef line);
-
獲取改行的上行高候址、下行高、行間距(行高)
double CTLineGetTypographicBounds(CTLineRef line, CGFloat *ascent, CGFloat *descent, CGFloat *leading);
//行高 lineHeightErrorDimension誤差 可以為0 lineSpace 設(shè)置的行間距
-(CGFloat)heightForCTLine: (CTLineRef)line{
CGFloat h = 0;
CGFloat ascent;
CGFloat descent;
CGFloat leading;
CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
h = MAX(h, ascent + descent + leading);
return h + _lineHeightErrorDimension + self.lineSpace;
}
//行間距的設(shè)置方式
- (void)addGlobalAttributeWithContent:(NSMutableAttributedString *)aContent font:(UIFont *)aFont
{
CGFloat lineLeading = self.lineSpace; // 行間距
const CFIndex kNumberOfSettings = 2;
// //設(shè)置段落格式
// CTParagraphStyleSetting lineBreakStyle;
// CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping;
// lineBreakStyle.spec = kCTParagraphStyleSpecifierLineBreakMode;
// lineBreakStyle.valueSize = sizeof(CTLineBreakMode);
// lineBreakStyle.value = &lineBreakMode;
//設(shè)置行距
CTParagraphStyleSetting lineSpaceStyle;
CTParagraphStyleSpecifier spec;
spec = kCTParagraphStyleSpecifierLineSpacingAdjustment;
lineSpaceStyle.spec = spec;
lineSpaceStyle.valueSize = sizeof(CGFloat);
lineSpaceStyle.value = &lineLeading;
// 結(jié)構(gòu)體數(shù)組
CTParagraphStyleSetting theSettings[kNumberOfSettings] = {
lineSpaceStyle,
};
CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings);
// 將設(shè)置的行距應(yīng)用于整段文字
[aContent addAttribute:NSParagraphStyleAttributeName value:(__bridge id)(theParagraphRef) range:NSMakeRange(0, aContent.length)];
// CFStringRef fontName = (__bridge CFStringRef)aFont.fontName;
// CTFontRef fontRef = CTFontCreateWithName(fontName, aFont.pointSize, NULL);
// // 將字體大小應(yīng)用于整段文字
// [aContent addAttribute:NSFontAttributeName value:(__bridge id)fontRef range:NSMakeRange(0, aContent.length)];
//
// // 給整段文字添加默認(rèn)顏色
// [aContent addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, aContent.length)];
// 內(nèi)存管理
CFRelease(theParagraphRef);
// CFRelease(fontRef);
}
CTRunRef
CTLineRef line = (__bridge CTLineRef)lines[i];
NSArray *runs = (NSArray*)CTLineGetGlyphRuns(line);
-
獲取改行的CTRun塊在該行的下標(biāo)位置
CFIndex CTRunGetGlyphCount(CTRunRef run);
-
獲取該行的CTRun塊在的物理坐標(biāo)位置
const CGPoint * CTRunGetPositionsPtr(CTRunRef run);
-
獲取改CTRun塊的寬度 返回值是邊界寬度
double CTRunGetTypographicBounds(CTRunRef run, CFRange range, CGFloat *ascent, CGFloat *descent, CGFloat *leading);