這裏能夠指定顯示的寬度,高度隨着文字的數量自動增長 看到這些是否是很開心,IM聊天記錄基本都是這樣的原理。 隨着輸入的字體自動增長,顯示的View的高度自動動態的增長架構
這裏介紹一下coreText,下面的一段話引用自唐巧博客
CoreText
是用於處理文字和字體的底層技術。它直接和Core Graphics
(又被稱爲 Quartz)打交道。Quartz 是一個 2D 圖形渲染引擎,可以處理 OSX 和 iOS 中的圖形顯示。 Quartz 可以直接處理字體(font)和字形(glyphs),將文字渲染到界面上,它是基礎庫中惟一可以處理字形的模塊。所以,CoreText 爲了排版,須要將顯示的文本內容、位置、字體、字形直接傳遞給 Quartz。相比其它 UI 組件,因爲 CoreText 直接和 Quartz 來交互,因此它具備高速的排版效果。 下圖是 CoreText 的架構圖,能夠看到,CoreText 處於很是底層的位置,上層的 UI 控件(包括 UILabel,UITextField 以及 UITextView)和 UIWebView
都是基於 CoreText 來實現的。mvc
model
裏面分三個類iview
YYGFrameParserConfig | YYGFrameParser | YYGCoreTextDat |
---|---|---|
1.YYGFrameParserConfig 類ide
既然要把內容呈現出來,就必須知道內容呈現的內容的一下呈現方式吧! 該類就是幹這個的。字體
須要知道
要顯示的寬度
ui
@property(nonatomic, assign) CGFloat width;
atom須要知道
要顯示的字體大小
spa
@property(assign,nonatomic) CGFloat fontSize;
rest須要知道
要顯示的行間距離
code
@property(assign,nonatomic) CGFloat lineSpace;
須要知道
要顯示的字體顏色
@property(strong,nonatomic) UIColor * textColor;
代碼以下
@interface YYGFrameParserConfig : NSObject
/** * view顯示的寬度 */
@property(nonatomic, assign) CGFloat width;
/** * 字體大小 */
@property(assign,nonatomic) CGFloat fontSize;
/** * 行間距離 */
@property(assign,nonatomic) CGFloat lineSpace;
/** * 字體顏色 */
@property(strong,nonatomic) UIColor * textColor;
@end
--------------------
.m文件
#import "YYGFrameParserConfig.h"
@implementation YYGFrameParserConfig
-(id)init
{
self=[super init];
if (self)
{
_width=200.0f;
_fontSize=16.0f;
_lineSpace=8.0f;
_textColor=RGB(108, 108, 108);
}
return self;
}
@end複製代碼
2.YYGFrameParser類
咱們都知道任何呈如今手機屏幕上的信息都是經過底層圖形渲染引擎來完成的,而在
UIView
裏面都是經過CTFrameDraw(CTFrameRef, CGContextRef)
來畫在畫布上的。 因此該類就是生成CTFrameRef
它的。 而生成這些要展示在View上的吧!就須要內容
!和對內容展示的一些約束,寬度,字體大小啊,而這些在上一個類中咱們已經完成啦!! 因此須要以下:須要
內容
須要
YYGFrameParserConfig
而最開始介紹過,經過內容能夠動態的生產
高度
這個纔是關鍵啊 因此須要返回高度
,和生成的CTFrameRef
返回
高度
返回
CTFrameRef
竟然返回倆參數,好吧直接再弄一個
model
因此有了下一個model類
本類代碼:
#import "YYGFrameParserConfig.h"
#import "YYGCoreTextData.h"
@interface YYGFrameParser : NSObject
+(YYGCoreTextData *)parseContent:(NSString *)content config:(YYGFrameParserConfig *)config;
@end
.m文件
#import "YYGFrameParser.h"
@implementation YYGFrameParser
+(YYGCoreTextData *)parseContent:(NSString *)content config:(YYGFrameParserConfig *)config
{
NSDictionary * dictionary=[self attributesWithConfig:config];
NSAttributedString * string=[[NSAttributedString alloc]initWithString:content attributes:dictionary];
// 建立 CTFramesetterRef 實例
CTFramesetterRef framesetter=CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
// 得到要繪製的區域的高度
CGSize restrictSize=CGSizeMake(config.width, CGFLOAT_MAX);
CGSize coreTextSize=CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0, 0), nil, restrictSize, nil);
CGFloat textHeight=coreTextSize.height;
// 生成 CTFrameRef 實例
CTFrameRef frameRef=[self createFrameWithFramesetter:framesetter config:config height:textHeight];
// 將生成好的 CTFrameRef 實例和計算好的繪製高度保存到 CoreTextData 實例中,最後返回 CoreTextData 實例
YYGCoreTextData *data=[[YYGCoreTextData alloc]init];
data.ctFram=frameRef;
data.height=textHeight;
CFRelease(frameRef);
CFRelease(framesetter);
return data;
}
+(NSDictionary *)attributesWithConfig:(YYGFrameParserConfig *)config
{
NSMutableDictionary * dict=[NSMutableDictionary dictionary];
//1
CGFloat fontSize=config.fontSize;
CTFontRef fontRef=CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
dict[(id)kCTFontAttributeName]=(__bridge id)fontRef;
CFRelease(fontRef);
//2
CGFloat lineSpace=config.lineSpace;
const CFIndex kNumberOfSetting=3;
CTParagraphStyleSetting theSettings[kNumberOfSetting]={
{kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpace},
{kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat),&lineSpace},
{kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpace}
};
CTParagraphStyleRef thePragraphRef=CTParagraphStyleCreate(theSettings, kNumberOfSetting);
dict[(id)kCTParagraphStyleAttributeName]=(__bridge id)thePragraphRef;
CFRelease(thePragraphRef);
//3
UIColor * textColor=config.textColor;
dict[(id)kCTForegroundColorAttributeName]=(__bridge id)textColor.CGColor;
return dict;
}
+(CTFrameRef )createFrameWithFramesetter:(CTFramesetterRef)framesetter config:(YYGFrameParserConfig *)config height:(CGFloat)height
{
CGMutablePathRef path=CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, config.width, height));
CTFrameRef frame=CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
CFRelease(path);
return frame;
}
@end複製代碼
3.YYGCoreTextData
它的出現來理由來自於上面的介紹
存儲生產的
CTFrameRef
@property(assign,nonatomic) CTFrameRef ctFram;
存儲生產的
動態生成的高度
@property(assign,nonatomic) CGFloat height;
.m文件
#import "YYGCoreTextData.h"
@implementation YYGCoreTextData
-(void)setCtFram:(CTFrameRef)ctFram
{
if (_ctFram!=ctFram)
{
if (_ctFram!=nil)
{
CFRelease(_ctFram);
}
CFRetain(ctFram);
_ctFram=ctFram;
}
}
-(void)dealloc
{
if (_ctFram!=nil)
{
CFRelease(_ctFram);
_ctFram=nil;
}
}
@end複製代碼
.h文件
@property(strong,nonatomic) YYGCoreTextData * data;
.m文件
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
if (self.data)
{
CTFrameDraw(self.data.ctFram, context);
}
}複製代碼
Category
方法#import <UIKit/UIKit.h>
@interface UIView (YYGView)
-(CGFloat)x;
-(void)setX:(CGFloat)x;
-(CGFloat)y;
-(void)setY:(CGFloat)y;
-(CGFloat)wide;
-(void)setWide:(CGFloat)wide;
-(CGFloat)height;
-(void)setHeight:(CGFloat)height;
@end
.m文件
#import "UIView+YYGView.h"
@implementation UIView (YYGView)
-(CGFloat)x
{
return self.frame.origin.x;
}
-(void)setX:(CGFloat)x
{
self.frame=CGRectMake(x, self.y, self.wide, self.height);
}
-(CGFloat)y
{
return self.frame.origin.y;
}
-(void)setY:(CGFloat)y
{
self.frame=CGRectMake(self.x, y, self.wide, self.height);
}
-(CGFloat)wide
{
return self.frame.size.width;
}
-(void)setWide:(CGFloat)wide
{
self.frame=CGRectMake(self.x, self.y, wide, self.height);
}
-(CGFloat)height
{
return self.frame.size.height;
}
-(void)setHeight:(CGFloat)height
{
self.frame=CGRectMake(self.x, self.y, self.wide, height);
}
@end複製代碼
什麼
Model
啊,UIview的category
的方法啊,都是爲了把東西畫在畫面上,就是爲YYGDisplayView
打輔助的,輔助其實很很重要!!!
.m文件
#import "YYGDisplayView.h"
@implementation YYGDisplayView
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
if (self.data)
{
CTFrameDraw(self.data.ctFram, context);
}
}
@end複製代碼
YYGFrameParserConfig * config=[[YYGFrameParserConfig alloc]init];
config.textColor=[UIColor purpleColor];
config.width=self.YYGView.wide;
YYGCoreTextData * data=[YYGFrameParser parseContent:@"韓美聯合參謀本部3日表示,朝鮮當天上午7時50分在黃海南道殷慄郡一帶朝日本海方向發射兩枚疑似「蘆洞」彈道導彈。其中一枚導彈發射不久便爆炸,另外一枚導彈飛越朝鮮境內、最終落在距日本秋田縣男鹿半島250千米的日本專屬經濟區,總飛行距離約1000千米。日本共同社分析,朝鮮此舉除了針對美韓外,還意在制約日本政府。而韓軍分析,朝鮮可能經過發射導彈進行武力示威,抗議在韓部署薩德反導系統,並試圖滋長韓國國內輿論分裂。" config:config];
self.YYGView.data=data;
self.YYGView.height=data.height;
self.YYGView.backgroundColor=[UIColor lightGrayColor];複製代碼