Core Text系列3 - CTLineDraw繪制細(xì)節(jié)控制

CTLineDraw細(xì)節(jié)繪制

首先得了解字形,如下圖:


字形圖.png

步驟

1.<code>CTFrameGetLines</code>函數(shù)獲取行數(shù)
2.<code>CTFrameGetLineOrigins</code>函數(shù)獲取每行的坐標(biāo)
3.<code>CTLineGetTypographicBounds(line as! CTLine, &lineAscent, &lineDescent, &lineLeading)</code>獲得每行的字形
4.<code>
CGContextSetTextPosition(ctx, lineOrigin.x, lineOrigin.y)</code>根據(jù)實際情況微調(diào)坐標(biāo)
5.<code>CTLineDraw(line as! CTLine, ctx)</code>繪制某一行缎除。

首先繪制大多數(shù)情況都要需要高度器罐,那么現(xiàn)在來一個高度計算的大致思路:

/*
     根據(jù)屬性字符串計算繪制所需要的高度
     思路就是 lineAscent+lineDescent +lineLeading代表一行的高度轰坊,分別對每一行進(jìn)行高度累加
     */
 func getDisplayHeight(attributeStr: NSAttributedString,width:CGFloat) -> CGFloat{
    
    let ctFrameSetter = CTFramesetterCreateWithAttributedString(attributeStr)
        
    //建議的寬高
    let suggestSize   =  CTFramesetterSuggestFrameSizeWithConstraints(ctFrameSetter, CFRangeMake(0, attributeStr.length), nil, CGSize(width: width, height: CGFloat.max), nil)
        
    let path =  CGPathCreateMutable()
        
    CGPathAddRect(path, nil, CGRect(x: 0, y: 0, width: width, height: suggestSize.height*2))//2是假的蕴忆,只是防止畫布不夠大驻襟,計算有誤沉衣,下面才開始精確計算高度
               
    let ctFrame = CTFramesetterCreateFrame(ctFrameSetter, CFRangeMake(0, 0), path, nil)
        
    let lines =  CTFrameGetLines(ctFrame) as Array
        
    var lineOrigins = Array<CGPoint>(count: lines.count, repeatedValue: CGPointZero)//獲取每一個行的坐標(biāo)
  
    CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), &lineOrigins)
    var lineAscent:CGFloat      = 0
    var lineDescent:CGFloat     = 0
    var lineLeading:CGFloat     = 0
    var lineTotalHeight:CGFloat = 0
        
    for (_,line) in lines.enumerate() {
          CTLineGetTypographicBounds(line as! CTLine, &lineAscent, &lineDescent, &lineLeading)
           let oneLineHeight = lineAscent+lineDescent + lineLeading//這里可以接上細(xì)節(jié)微調(diào)豌习,來返回高度
           lineTotalHeight += oneLineHeight
        }
        //高度就這么計算好了
        return lineTotalHeight
    
    }

CTLineDraw繪制肥隆,就是將CTFrameDraw拆分而已

override func drawInContext(ctx: CGContext) {
       super.drawInContext(ctx)
       
       //坐標(biāo)系轉(zhuǎn)換
       CGContextSetTextMatrix(ctx, CGAffineTransformIdentity)
       CGContextTranslateCTM(ctx, 0, self.bounds.size.height)
       CGContextScaleCTM(ctx, 1.0, -1.0)
       
       //創(chuàng)建繪制的區(qū)域
       let path = CGPathCreateMutable()
       CGPathAddRect(path, nil, self.bounds)
       
       // 4.創(chuàng)建需要繪制的文字
       let attributed =  NSMutableAttributedString(string: "估后共和國開不開vbdkaph估后共和國開不開vbdkaph??????????????????????????????????????????????????????????????這是我的第一個coreText demo,我是要給兵來自老白干I型那個餓哦個呢給個I類回滾igkhpwfh 評估后共和國開不開vbdkaphphohghg 的分工額好幾個遼寧省更怕hi維護(hù)你不看hi好人佛【井柏然把餓哦個?");
       
       attributed.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(20), range: NSMakeRange(0, 5));
       
       attributed.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(3, 10));
       
       attributed.addAttribute(NSForegroundColorAttributeName, value: UIColor.orangeColor(), range: NSMakeRange(0, 2));
       
       //創(chuàng)建段落屬性
       let paraStyle = NSMutableParagraphStyle()
       attributed.addAttribute(NSParagraphStyleAttributeName, value: paraStyle, range: NSMakeRange(0, attributed.length))
       
       //根據(jù)計算的高度畫一個比邊框 start
       let strockeHegith = self.getDisplayHeight(attributed, width: ScreenWidth)
       
       CGContextSaveGState(ctx)
       
       CGContextSetTextMatrix(ctx, CGAffineTransformIdentity)
       CGContextTranslateCTM(ctx, 0, self.bounds.size.height)
       CGContextScaleCTM(ctx, 1.0, -1.0)
       
       let strokePath = CGPathCreateMutable()
       
       CGPathAddRect(strokePath, nil, CGRect(x: 1, y: 1, width: ScreenWidth-2, height: strockeHegith))
       
       CGContextAddPath(ctx, strokePath)
       
       CGContextSetStrokeColorWithColor(ctx, UIColor.purpleColor().CGColor)
       
       CGContextStrokePath(ctx)
       
       CGContextRestoreGState(ctx)
       //根據(jù)計算的高度畫一個比邊框 end
       
       let ctFrameSetter = CTFramesetterCreateWithAttributedString(attributed)
       
       let ctFrame = CTFramesetterCreateFrame(ctFrameSetter, CFRangeMake(0, attributed.length), path, nil)
       
       
       let lines = CTFrameGetLines(ctFrame) as NSArray
       var originsArray = Array<CGPoint>(count: lines.count, repeatedValue: CGPointZero)//用于存儲每一行的坐標(biāo)
       
       CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), &originsArray)
       
       var frameY:CGFloat              = 0
       let kGlobalLineLeading:CGFloat  = 0
       
       for (i,line) in lines.enumerate() {
           var lineAscent:CGFloat      = 0
           var lineDescent:CGFloat     = 0
           var lineLeading:CGFloat     = 0
           CTLineGetTypographicBounds(line as! CTLine, &lineAscent, &lineDescent, &lineLeading)
           
           var   lineOrigin = originsArray[i];

           if (i > 0)
           {
           
               frameY = frameY - kGlobalLineLeading - lineAscent;//減去一個行間距凿宾,再減去第二行初厚,字形的上部分 (循環(huán))
               
               lineOrigin.y = frameY;
               
           } else
           {
              
               frameY = lineOrigin.y;
           }
           
           // 調(diào)整成所需要的坐標(biāo)
           CGContextSetTextPosition(ctx, lineOrigin.x, lineOrigin.y);
           CTLineDraw(line as! CTLine, ctx);
           
           
           frameY = frameY - lineDescent//說明下這里,就是減去字形下面部分
           
       }
   }
效果圖如下

總結(jié):因為有中文,英文和表情的存在蕾久,默認(rèn)情況下這三種的行高都是不等的,可以用上面的方法微調(diào)行高障簿,使其所有情況下都是等高的栅迄。

為所需顯示的最后一行添加省略號

步驟:
1.獲取所需操作行的range
2.獲取需要干掉字符的屬性
3.將獲取的屬性,添加給省略號屬性
4.剩下的字符串拼接上省略號
5.創(chuàng)建一個全新的CTLine繪制
6.繪制CTLine
mark:7.別傻傻的西篓,省略號在這里就是一個表示岂津,可以用是任何東西

//處理最后一行吮成,將最后一個字符干掉粱甫,并且加上省略號
            let lCharacter = "……"
            if i == lines.count - 1 {
                let lastLineRange           = CTLineGetStringRange(line as! CTLine)
                let lastCharAttribute       =   attributed.attributesAtIndex(attributed.length - 1, effectiveRange: nil)
                let lastAppentAttributeStr  = NSAttributedString(string: lCharacter, attributes: lastCharAttribute)
                let foreAttributeStr        =  attributed.attributedSubstringFromRange(NSMakeRange(lastLineRange.location, lastLineRange.length - 2)) as! NSMutableAttributedString//這里減去2是因為后面有個結(jié)尾的符號茶宵,c語言里面的“/n”
                let afterAttributeStr        =  attributed.attributedSubstringFromRange(NSMakeRange(lastLineRange.location + lastLineRange.length - 1, 1)) as! NSMutableAttributedString
                print("after:\\(afterAttributeStr.string)測試")
                foreAttributeStr.appendAttributedString(lastAppentAttributeStr)
                let createLastline = CTLineCreateWithAttributedString(foreAttributeStr)
                CTLineDraw(createLastline, ctx)
            }else{
                CTLineDraw(line as! CTLine, ctx)
            }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末属韧,一起剝皮案震驚了整個濱河市宵喂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淌山,老刑警劉巖顾瞻,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件退渗,死亡現(xiàn)場離奇詭異会油,居然都是意外死亡翻翩,警方通過查閱死者的電腦和手機(jī)嫂冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門忱屑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莺戒,“玉大人从铲,你說我怎么就攤上這事名段∩毂伲” “怎么了信夫?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵警没,是天一觀的道長杀迹。 經(jīng)常有香客問我浅碾,道長及穗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮懂版,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓬抄。我一直安慰自己嚷缭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著着帽,像睡著了一般仍翰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灵迫,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天三圆,我揣著相機(jī)與錄音修噪,去河邊找鬼黄琼。 笑死脏款,一個胖子當(dāng)著我的面吹牛撤师,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播万俗,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蓖墅,長吁一口氣:“原來是場噩夢啊……” “哼教翩!你這毒婦竟也來了蚜退?” 一聲冷哼從身側(cè)響起配猫,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凡伊,沒想到半個月后零渐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡系忙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惠豺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片银还。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洁墙,靈堂內(nèi)的尸體忽然破棺而出蛹疯,到底是詐尸還是另有隱情,我是刑警寧澤热监,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布捺弦,位于F島的核電站,受9級特大地震影響孝扛,放射性物質(zhì)發(fā)生泄漏列吼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一苦始、第九天 我趴在偏房一處隱蔽的房頂上張望寞钥。 院中可真熱鬧,春花似錦陌选、人聲如沸理郑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽您炉。三九已至柒爵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赚爵,已是汗流浹背棉胀。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留囱晴,地道東北人膏蚓。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像畸写,于是被迫代替她去往敵國和親驮瞧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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

  • 1.iOS中的round枯芬、ceil论笔、floor函數(shù)略解 round如果參數(shù)是小數(shù),則求本身的四舍五入.ceil如果...
    K_Gopher閱讀 1,186評論 1 0
  • 版本記錄 前言 Core Text框架主要用來做文字處理千所,是的iOS3.2+和OSX10.5+中的文本引擎狂魔,讓您精...
    刀客傳奇閱讀 953評論 0 1
  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標(biāo)簽 ②:HTML5 ...
    GreenHand1閱讀 4,685評論 2 32
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,180評論 25 707
  • 《蚊子》 東面山墻有一只蚊子 我讓它吸干我的血 我猜是你派來的 《騙子》 我不是想睡你 畢竟我是臟的 我只想跟你數(shù)...
    87b2ca3db634閱讀 441評論 2 4