版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。
訓示根視圖:(準備幾張圖檔,把label加載在window上)
customlable *label = [[customlable alloc]initwithframe:cgrectmake(0, 60, self.window.bounds.size.width, self.window.bounds.size.height)];
label.backgroundcolor = [uicolor greencolor];
[self.window addsubview:label];
引進架構:
#import <coretext/coretext.h>
建一個類,繼承自uilabel
傳回圖檔的高:
// 傳回圖檔的高
cgfloat rundelegategetascentcallback(voidvoid *refcon) {
nsstring *imagename = (__bridge nsstring *)refcon;
return [uiimage imagenamed:imagename].size.height;
}
傳回圖檔的寬:
// 傳回圖檔的寬
cgfloat rundelegategetwidthcallback(voidvoid *refcon) {
// nsstring *imagename = (__bridge nsstring *)refcon;
// 讓繪制圖檔的寬度為螢幕的寬, 使文本中隻要遇到圖檔就換行(配合上面的換行模式)
// 如果不想換行可以直接傳回圖檔的寬
return [uiscreen mainscreen].bounds.size.width;
cgfloat rundelegategetdescentcallback(voidvoid *refcon){
return 0;
開始繪制及相關計算:
#import "customlable.h"
#import <coretext/coretext.h>
@implementation customlable
- (void)drawrect:(cgrect)rect
{
[super drawrect:rect];
// 建立繪制區域
cgmutablepathref path = cgpathcreatemutable();
cgpathaddrect(path, nil, cgrectmake(0, 0, self.bounds.size.width, self.bounds.size.height));
// 擷取目前用于繪制畫布的上下文, 用于後續将内容繪制到畫布上
cgcontextref context = uigraphicsgetcurrentcontext();
// 翻轉坐标系
// 參數1:文本寬度占label的比例(0 ~ 1)
// 參數2:水準方向文字逐漸往下(參數 > 0, 往上: 參數 < 0)偏移,如果是正數,逐漸向上偏移
// 參數3:在豎直方向上,從下往上每行文字逐漸往右(參數 > 0, 往左: 參數 < 0)偏移
// 參數4:文本首行的縱坐标占label的比例(-1 ~ 0)
// 參數5:文本整體往右(參數 > 0, 往左: 參數 < 0)偏移量
// 參數6:文本整體在縱坐标方向的偏移量,參數 > label的高度, 往下偏移, 參數 < label的高度, 往上偏移
cgcontextconcatctm(context, cgaffinetransformmake(1, 0, 0, -1, 0, self.bounds.size.height));
// 準備文本
nsmutableattributedstring *attrstring = [[nsmutableattributedstring alloc]initwithstring:@"ios程式在啟動時會建立一個主線程,而在一個線程隻能執行一件事情,如果在主線程執行某些耗時操作,例如加載網絡圖檔,下載下傳資源檔案等會阻塞主線程(導緻界面卡死,無法互動),是以就需要使用多線程技術來避免這類情況。ios中有三種多線程技術 nsthread,nsoperation,gcd,這三種技術是随着ios發展引入的,抽象層次由低到高,使用也越來越簡單。"];
// 改變字型大小
[attrstring addattribute:nsfontattributename value:[uifont systemfontofsize:24] range:nsmakerange(0, 5)];
// 改變字型顔色
[attrstring addattribute:nsforegroundcolorattributename value:[uicolor redcolor] range:nsmakerange(0, 5)];
// 換行模式 (當label的寬度不夠顯示内容或圖檔的時候就自動換行) (預設狀态下如果不夠顯示圖檔, 不會自動換行, 部分圖檔就會看不見)
ctparagraphstylesetting linebreakmode;
ctlinebreakmode linebreak = kctlinebreakbycharwrapping;
linebreakmode.spec = kctparagraphstylespecifierlinebreakmode;
linebreakmode.value = &linebreak;
linebreakmode.valuesize = sizeof(ctlinebreakmode);
ctparagraphstylesetting setting[] = {linebreakmode};
ctparagraphstyleref style = ctparagraphstylecreate(setting, 1);
nsmutabledictionary *attributes = [nsmutabledictionary dictionarywithobject:(__bridge id)style forkey:(id)kctparagraphstyleattributename];
[attrstring addattributes:attributes range:nsmakerange(0, attrstring.length)];
// 設定ctrundelegatecallbacks 擷取圖檔大小
ctrundelegatecallbacks imagecallbacks;
imagecallbacks.version = kctrundelegateversion1;
// 擷取圖檔的高 (可自由設定傳回的高)
imagecallbacks.getascent = rundelegategetascentcallback;
// 設定圖檔下一行文字距離圖檔的距離
imagecallbacks.getdescent = rundelegategetdescentcallback;
// 擷取圖檔的寬 (可自由設定傳回寬度)
imagecallbacks.getwidth = rundelegategetwidthcallback;
// 空格用于給圖檔留個位置
nsmutableattributedstring *imageattributedstring = [[nsmutableattributedstring alloc]initwithstring:@" "];
// 根據圖檔占用尺寸的大小給圖檔留位置顯示
ctrundelegateref rundelegate = ctrundelegatecreate(&imagecallbacks, (__bridge voidvoid *)(@"untitled.png"));
[imageattributedstring addattribute:(nsstring *)kctrundelegateattributename value:(__bridge id)rundelegate range:nsmakerange(0, 1)];
// 将圖檔顯示在指定位置
nsstring *imagekey = @"imagename";
[imageattributedstring addattribute:imagekey value:@"untitled.png" range:nsmakerange(0, 1)];
// 設定插入圖檔的位置
[attrstring insertattributedstring:imageattributedstring atindex:38];
//根據nsmutableattributedstring生成frame
ctframeref frame = ctframesettercreateframe(ctframesettercreatewithattributedstring((cfattributedstringref)attrstring), cfrangemake(0, attrstring.length), path, nil);
// 開始繪制
ctframedraw(frame, context);
cfarrayref lines = ctframegetlines(frame);
cgpoint lineorigins[cfarraygetcount(lines)];
ctframegetlineorigins(frame, cfrangemake(0, 0), lineorigins);
for (int i = 0; i < cfarraygetcount(lines); i++) {
ctlineref line = cfarraygetvalueatindex(lines, i);
cfarrayref runs = ctlinegetglyphruns(line);
for (int j = 0; j < cfarraygetcount(runs); j++) {
cgfloat runascent;
cgfloat rundescent;
cgpoint lineorigin = lineorigins[i];
ctrunref run = cfarraygetvalueatindex(runs, j);
nsdictionary *mattrinbutes = (nsdictionary *)ctrungetattributes(run);
cgrect runrect;
runrect.size.width = ctrungettypographicbounds(run, cfrangemake(0, 0), &runascent, &rundescent, null);
runrect = cgrectmake(lineorigin.x + ctlinegetoffsetforstringindex(line, ctrungetstringrange(run).location, null), lineorigin.y - rundescent, runrect.size.width, runascent + rundescent);
nsstring *imagename = [mattrinbutes objectforkey:imagekey];
// 圖檔的渲染邏輯
if (imagename) {
uiimage *image = [uiimage imagenamed:imagename];
cgrect imagedrawrect;
imagedrawrect.size = image.size;
/*
* 這才是放置圖檔的真正坐标
*/
// 設定圖檔的在x坐标的位置
// imagedrawrect.origin.x = runrect.origin.x + lineorigin.x;
// 将圖檔放在label的中間
imagedrawrect.origin.x = (self.bounds.size.width - image.size.width) / 2;
// 設定圖檔在y坐标的位置
imagedrawrect.origin.y = lineorigin.y;
// 繪制圖檔
cgcontextdrawimage(context, imagedrawrect, image.cgimage);
}
}
}
最終效果:
原文位址:http://blog.csdn.net/qq_31810357/article/details/50124869