對(duì)唐巧CoreText圖文混排修改悬钳,加入背景,透明度棘捣,縮進(jìn)等操作等

需求需要修改背景辜腺,加入背景色,透明度操作等乍恐,由于時(shí)間比較緊评疗,就在原有基礎(chǔ)上修改,現(xiàn)有代碼用的是唐巧寫的CoreText圖文混排

之前的左下角聊天的效果:

image

做好后的效果左下角:

image

排版引擎框架

對(duì)于一個(gè)復(fù)雜的排版引擎來說禁熏,可以將其功能拆成以下幾個(gè)類來完成:

  1. 一個(gè)顯示用的類壤巷,僅負(fù)責(zé)顯示內(nèi)容,不負(fù)責(zé)排版
  2. 一個(gè)模型類瞧毙,用于承載顯示所需要的所有數(shù)據(jù)
  3. 一個(gè)排版類胧华,用于實(shí)現(xiàn)文字內(nèi)容的排版
  4. 一個(gè)配置類寄症,用于實(shí)現(xiàn)一些排版時(shí)的可配置項(xiàng)
    注:” 單一功能原則 “(Single responsibility principle)
    參考鏈接:http://zh.wikipedia.org/wiki/%E5%8D%95%E4%B8%80%E5%8A%9F%E8%83%BD%E5%8E%9F%E5%88%99

按照以上原則,我們將CTDisplayView中的部分內(nèi)容拆開矩动,由 4 個(gè)類構(gòu)成:

  1. CTFrameParserConfig類有巧,用于配置繪制的參數(shù),例如:文字顏色悲没,大小篮迎,行間距等。
  2. CTFrameParser類示姿,用于生成最后繪制界面需要的CTFrameRef實(shí)例甜橱。
  3. CoreTextData類,用于保存由CTFrameParser類生成的CTFrameRef實(shí)例以及CTFrameRef實(shí)際繪制需要的高度栈戳。
  4. CTDisplayView類岂傲,持有CoreTextData類的實(shí)例,負(fù)責(zé)將CTFrameRef繪制到界面上子檀。

關(guān)于這 4 個(gè)類的關(guān)鍵代碼镊掖,自己去看源碼吧,關(guān)于CoreText的原理褂痰,實(shí)現(xiàn)亩进,可以去看唐巧博客,源碼寫的很好缩歪,適應(yīng)了他當(dāng)時(shí)的業(yè)務(wù)需求归薛,同樣有些問題,比如寬度固定匪蝙,CTDisplayView繪制的時(shí)候背景色不知道怎么傳

以前的效果圖苟翻,寬度固定,無背景骗污,無圓角

首先修改寬度

CTFrameParser 類負(fù)責(zé)把 NSAttributedString 的基礎(chǔ)數(shù)據(jù) 和 CTFrameParserConfig 的配置信息生成CoreTextData類崇猫, CoreTextData用于保存由CTFrameParser類生成的CTFrameRef實(shí)例以及CTFrameRef實(shí)際繪制需要的高度。

CTFrameParser類
去掉 if (data.height > 18.0) ,讓寬度跟隨計(jì)算出來的寬度需忿,不用以前固定的寬度

+ (CoreTextData *)parseAttributedContent:(NSAttributedString *)content config:(CTFrameParserConfig *)config {
// 創(chuàng)建CTFramesetterRef實(shí)例
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)content);

// 獲得要緩制的區(qū)域的高度
CGSize restrictSize = CGSizeMake(config.width, CGFLOAT_MAX);
CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), nil, restrictSize, nil);
CGFloat textHeight = coreTextSize.height;

// 生成CTFrameRef實(shí)例
CTFrameRef frame = [self createFrameWithFramesetter:framesetter config:config height:textHeight];

// 將生成好的CTFrameRef實(shí)例和計(jì)算好的緩制高度保存到CoreTextData實(shí)例中诅炉,最后返回CoreTextData實(shí)例
CoreTextData *data = [[CoreTextData alloc] init];

data.ctFrame = frame;
data.height = textHeight;
data.content = content;

//獲得要緩制的區(qū)域的寬度
//    if (data.height > 18.0) {
//        data.width = config.width;
//    } else
{
    CGSize restrictSize = CGSizeMake(CGFLOAT_MAX, textHeight);
    CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), nil, restrictSize, nil);
    CGFloat textWidth = coreTextSize.width;
    data.width = textWidth;
}

if(data.width > config.width)
{
    data.width = config.width;
}

// 釋放內(nèi)存
CFRelease(frame);
CFRelease(framesetter);
return data;
}

其次修改背景和半透明

我發(fā)現(xiàn)在初始化 CTDisplayView 的地方怎么設(shè)置背景顏色都沒用,永遠(yuǎn)是白色
只有設(shè)置成clearColor 清掉背景色起作用屋厘,用的是YYAsyncLayer做的繪制

  • (void)_displayAsync:(BOOL)async里面沒有背景色的時(shí)候默認(rèn)就是白色涕烧,修改了默認(rèn)顏色
  • [UIColor colorWithWhite:0.0f alpha:0.3f].CGColor
  • 修改了,繪制時(shí)候默認(rèn)不透明修改為透明.
    UIGraphicsBeginImageContextWithOptions(size, NO, scale)

然后修改圓角

可以看看圓角的幾種實(shí)現(xiàn)方式
http://www.cnblogs.com/mafeng/p/5672528.html

在DTMessageCell里面
- (void)updateUI {
if (![self.contentView.subviews containsObject:self.displayView]) {
[self.contentView addSubview:self.displayView];
}

CGFloat width = self.displayView.data.width;
CGFloat height = self.displayView.data.height;
self.displayView.frame = CGRectMake(0.0, 2.0, width, height);

CGRect bound = CGRectZero;
bound.size.width = width;
bound.size.height = height;
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.path = [[UIBezierPath bezierPathWithRoundedRect:bound
                                        byRoundingCorners:UIRectCornerAllCorners
                                              cornerRadii:CGSizeMake(10, 10)] CGPath];
self.displayView.layer.mask = maskLayer;

}

修改縮進(jìn)

前面這些都改完之后發(fā)現(xiàn)左右的邊距是貼著邊框的
在CTFrameParserConfig里面加了三個(gè)參數(shù)

  1. firstLineHeadIndent
  2. headIndent
  3. tailIndent
修改CTFrameParser
+ (NSMutableDictionary *)attributesWithConfig:(CTFrameParserConfig *)config {
CGFloat fontSize = config.fontSize;
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
CGFloat lineSpacing = config.lineSpace;
const CFIndex kNumberOfSettings = 4;
uint8_t breakMode = kCTLineBreakByWordWrapping;
CTParagraphStyleSetting theSettings[kNumberOfSettings] = {
    { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat),         &lineSpacing },
    { kCTParagraphStyleSpecifierMaximumLineSpacing,    sizeof(CGFloat),         &lineSpacing },
    { kCTParagraphStyleSpecifierMinimumLineSpacing,    sizeof(CGFloat),         &lineSpacing },
    { kCTParagraphStyleSpecifierLineBreakMode,         sizeof(uint8_t),         &breakMode   }
};


CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings);

UIColor *textColor = config.textColor;

NSMutableDictionary *dict = [NSMutableDictionary dictionary];


dict[(id)kCTForegroundColorAttributeName] = (id)textColor.CGColor;
dict[(id)kCTFontAttributeName] = (__bridge id)fontRef;
dict[(id)kCTParagraphStyleAttributeName] = (__bridge id)theParagraphRef;



NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
//縮進(jìn)
paragraphStyle.firstLineHeadIndent = config.firstLineHeadIndent;
paragraphStyle.headIndent = config.headIndent;
paragraphStyle.tailIndent = -config.tailIndent;
dict[(id)NSParagraphStyleAttributeName] = paragraphStyle;



CFRelease(theParagraphRef);
CFRelease(fontRef);
return dict;
}

一個(gè)小坑

小屏手機(jī)上屏蔽掉了 YYAsyncLayer 汗洒,不知道唐巧做何考慮,看YYKit作者的博客议纯,是支持4s的,4s依然很流暢
+ (Class)layerClass {
//    if (kScreenWidth <= 321) {
//        return [CALayer class];
//    }
return [YYAsyncLayer class];
}

后續(xù)補(bǔ)充需求,首行距離頂部距離修改溢谤,尾行距離底部距離修改

聊天高度加10
CTFrameParser.m

  • (CoreTextData *)parseAttributedContent:(NSAttributedString *)content config:(CTFrameParserConfig *)config
    data.height = textHeight += 10;

文字往上移5像素

  • (NSMutableDictionary *)attributesWithConfig:(CTFrameParserConfig *)config

dict[(id)NSBaselineOffsetAttributeName] = @(5);

  • (void)fillImagePosition {
    圖片往上移5像素
    CoreTextData.m
    runBounds.origin.y -= descent - 5;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞻凤,一起剝皮案震驚了整個(gè)濱河市憨攒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阀参,老刑警劉巖肝集,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蛛壳,居然都是意外死亡杏瞻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門衙荐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捞挥,“玉大人,你說我怎么就攤上這事忧吟∈魉啵” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵瀑罗,是天一觀的道長。 經(jīng)常有香客問我雏掠,道長斩祭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任乡话,我火速辦了婚禮摧玫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绑青。我一直安慰自己诬像,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布闸婴。 她就那樣靜靜地躺著坏挠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邪乍。 梳的紋絲不亂的頭發(fā)上降狠,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音庇楞,去河邊找鬼榜配。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吕晌,可吹牛的內(nèi)容都是我干的蛋褥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼睛驳,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼烙心!你這毒婦竟也來了膜廊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤弃理,失蹤者是張志新(化名)和其女友劉穎溃论,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痘昌,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钥勋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辆苔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片算灸。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驻啤,靈堂內(nèi)的尸體忽然破棺而出菲驴,到底是詐尸還是另有隱情,我是刑警寧澤骑冗,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布赊瞬,位于F島的核電站,受9級(jí)特大地震影響贼涩,放射性物質(zhì)發(fā)生泄漏巧涧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一遥倦、第九天 我趴在偏房一處隱蔽的房頂上張望谤绳。 院中可真熱鬧,春花似錦袒哥、人聲如沸缩筛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞎抛。三九已至,卻和暖如春却紧,著一層夾襖步出監(jiān)牢的瞬間婿失,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工啄寡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豪硅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓挺物,卻偏偏與公主長得像懒浮,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫砚著、插件次伶、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,093評(píng)論 4 62
  • Beats這個(gè)項(xiàng)目的確很好用,幾行命令下來稽穆,一個(gè)成型的Agent就出來了冠王。使用者只需要關(guān)注采集什么數(shù)據(jù)就好,后續(xù)的...
    小埋醬閱讀 946評(píng)論 0 0
  • 一舌镶、從反手區(qū)網(wǎng)前接發(fā)+后側(cè)頭頂區(qū)殺斜線 (黃衣網(wǎng)前接發(fā)回放+頭頂區(qū)殺斜線柱彻;側(cè)面視角) (黃衣網(wǎng)前接發(fā)回放+頭頂區(qū)殺...
    金教練閱讀 429評(píng)論 0 0