iOS中運用coreText 進行文字自適應

先看看效果圖

這裏能夠指定顯示的寬度,高度隨着文字的數量自動增長 看到這些是否是很開心,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

搞MVC理念來實現

model裏面分三個類iview

YYGFrameParserConfig YYGFrameParser YYGCoreTextDat

Model

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複製代碼

View

.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);
    }
}複製代碼

好吧還須要從寫 UIView 的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複製代碼

YYGDisplayView 類

什麼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複製代碼

Controller如今開始調用了

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];複製代碼
相關文章
相關標籤/搜索