★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公衆號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:http://www.javashuo.com/article/p-nucxsjno-mc.html
➤若是連接不是山青詠芝的博客園地址,則多是爬取做者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持做者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★html
目錄:[Swift]通天遁地Swiftgit
本文將演示CoreText框架實現圖文混排。CoreText(富文本)框架並不支持圖片的繪製,github
須要藉助Core Graphics框架來進行圖片的繪製。swift
圖文混排的實現原理很是簡單,就是在一個富文本中插入一個佔位符,數組
表示此處須要插入一張圖片。而後再由另外一個圖形繪製框架,微信
在佔位符所在位置繪製指定的圖片。app
在項目文件夾上點擊鼠標右鍵,彈出右鍵菜單。框架
【New File】->【Cocoa Touch】->【Next】->ide
【Class】:CTImageView函數
【Subclass of】:UIView
【Language】:Swift
->【Next】->【Create】
點擊打開【CTImageView.swift】,如今開始編寫代碼,建立一個包含多行文字的段落。
1 import UIKit 2 3 //在類名的上方,添加兩個浮點類型的全局變量,表示在富文本中插入的圖片等尺寸。 4 let picWidth = CGFloat(200.0) 5 let picHeight = CGFloat(133.0) 6 7 class CTImageView: UIView 8 { 9 //實現視圖的繪製方法 10 override func draw(_ rect: CGRect) 11 { 12 super.draw(rect) 13 14 //設置填充顏色爲橙色 15 UIColor.orange.setFill() 16 //在視圖的顯示區域填充橙色 17 UIRectFill(rect) 18 19 //得到圖片佔位符的尺寸信息, 20 //該方法依次設置了,佔位符的基線至佔位符頂部的距離, 21 //基線至佔位符底部的距離,和佔位符寬度三個尺寸的數據。 22 var ctRunCallback = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, 23 dealloc:{ (refCon) -> Void in}, 24 getAscent: { ( refCon) -> CGFloat in return picHeight}, 25 getDescent: { (refCon) -> CGFloat in return 0 26 }){ (refCon) -> CGFloat in 27 return picWidth 28 } 29 30 //初始化一個字符串變量,設置待插入的圖片在項目文件夾中的名稱。 31 var picture = "coffee" 32 //建立一個代理對象,做爲佔位符的代理屬性。 33 let ctRunDelegate = CTRunDelegateCreate(&ctRunCallback, &picture) 34 //建立一個可變屬性的字符串對象,做爲待插入圖片的佔位符, 35 //它的內容就是一個簡單的空格 36 let placeHolder = NSMutableAttributedString(string: " ") 37 38 //設置佔位符屬性的值,這樣當繪製圖片時,能夠從該屬性中,得到待繪製圖片的位置和尺寸信息。 39 placeHolder.addAttribute(kCTRunDelegateAttributeName as NSAttributedString.Key, 40 value: ctRunDelegate!, range: NSMakeRange(0, 1)) 41 //繼續給佔位符添加一個自定義的屬性,並設置屬性的值爲圖片的名稱, 42 //這樣當繪製圖片時,能夠從該屬性中,得到待繪製圖片的名稱。 43 placeHolder.addAttribute(NSAttributedString.Key(rawValue: "pictureName"), 44 value: picture, range: NSMakeRange(0, 1)) 45 46 //建立一個字符串常量,表示富文本的內容。 47 //圖片將被插入到字符串的兩個換行符之間的位置。 48 let article = "Coffee is a brewed drink prepared from roasted coffee beans, which are the seeds of berries from the Coffea plant.\n\nThe genus Coffea is native to tropical Africa, and Madagascar, the Comoros, Mauritius and Réunion in the Indian Ocean." 49 //經過一個字符串常量,建立一個富文本字符串。 50 let attributedStr = NSMutableAttributedString(string: article) 51 52 //將圖片佔位符插入到兩個換行符之間的位置。 53 attributedStr.insert(placeHolder, at: 115) 54 //給富文本添加下劃線樣式, 55 attributedStr.addAttribute(kCTUnderlineStyleAttributeName as NSAttributedString.Key, 56 value: 1, range: NSRange(location: 0, length: attributedStr.length)) 57 58 //經過富文本對象,得到幀設置器,也就是幀的工廠類。 59 let framesetter = CTFramesetterCreateWithAttributedString(attributedStr) 60 //設置以當前的顯示區域,做爲繪製的區域。 61 let path = UIBezierPath(rect: rect) 62 //得到用於繪製的幀對象。 63 let ctFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedStr.length), path.cgPath, nil) 64 65 //在繪製以前,須要指定繪製的圖形上下文,在此得到當前的圖形上下文。 66 let crtContext = UIGraphicsGetCurrentContext() 67 //因爲兩個礦建的座標系統的原點位置不一樣,因此須要對上下文進行一些變形操做, 68 //首先設置圖形上下文的字體矩陣。 69 crtContext!.textMatrix = CGAffineTransform.identity 70 //而後對圖形上下文進行翻轉。 71 crtContext?.scaleBy(x: 1.0, y: -1.0) 72 //再對圖形上下文進行平移操做。 73 crtContext?.translateBy(x: 0, y: self.bounds.size.height * -1) 74 //使用幀繪製函數,將幀對象,繪製在指定的圖形上下文中。 75 CTFrameDraw(ctFrame, crtContext!) 76 77 //此時雖然咱們尚未在富文本中插入圖片,可是富文本已經擁有了標誌符, 78 //因此在渲染時會自動保留指定的區域,等待圖片的渲染。 79 //本條語句用來從幀對象中,得到了全部的行對象。 80 let ctLines = CTFrameGetLines(ctFrame) as NSArray 81 //建立一個座標點類型的數組,用來存儲每一行文字原點的位置。 82 var originsOfLines = [CGPoint]() 83 //經過一個循環語句, 84 for _ in 0..<ctLines.count 85 { 86 //將原點座標存儲在數組中。 87 originsOfLines.append(CGPoint.zero) 88 } 89 90 //初始化一個範圍對象 91 let range: CFRange = CFRangeMake(0, 0) 92 //設置每一行文字原點的位置 93 CTFrameGetLineOrigins(ctFrame, range, &originsOfLines) 94 95 //如今能夠進行圖片的繪製工做了,因爲佔位符處於CTRun對象中, 96 //因此咱們首先經過一個循環語句,對行數組,即6行的文字內容進行遍歷。 97 for i in 0..<ctLines.count 98 { 99 //得到當前行的原點位置 100 let ctLineOrigin = originsOfLines[i] 101 //得到當前行中的全部指定對象的數組 102 let ctRuns = CTLineGetGlyphRuns(ctLines[i] as! CTLine) as NSArray 103 104 //經過一個循環語句,對數組進行遍歷操做。 105 for ctRun in ctRuns 106 { 107 //得到遍歷到的對象的屬性字典 108 let ctAttributes = CTRunGetAttributes(ctRun as! CTRun) as NSDictionary 109 //得到字典中的圖片名稱屬性 110 let pictureName = ctAttributes.object(forKey: "pictureName") 111 //經過判斷圖片名稱是否爲空,來檢測當前的對象,是不是插入的那個圖片的佔位符 112 if pictureName != nil 113 { 114 //得到遍歷到的對象, 115 //在一行中的水平方向上的便宜距離 116 let offset = CTLineGetOffsetForStringIndex(ctLines[i] as! CTLine, CTRunGetStringRange(ctRun as! CTRun).location, nil) 117 //得到待繪製的圖片,在水平方向上的位置 118 let picturePosX = ctLineOrigin.x + offset 119 //經過當前行的原點,水平偏移和圖片的尺寸信息, 120 //建立一個圖片將被繪製的目標區域。 121 let pictureFrame = CGRect(x: picturePosX, y: ctLineOrigin.y, width: picWidth, height: picHeight) 122 //根據得到的圖片名稱屬性,從項目文件夾中,讀取指定名稱的圖片。 123 let image = UIImage(named: pictureName as! String) 124 //最後將圖片繪製在指定佔位區域。 125 crtContext?.draw((image?.cgImage)!, in: pictureFrame) 126 } 127 } 128 } 129 } 130 }
至此就完成了圖片混排視圖的全部編碼工做。
在左側的項目導航區,打開視圖控制器的代碼文件【ViewController.swift】
1 import UIKit 2 3 class ViewController: UIViewController { 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 // Do any additional setup after loading the view, typically from a nib. 8 9 //在視圖加載完成的方法中,使用上文剛剛建立的自定義視圖。 10 //初始化一個自定義的視圖對象。 11 let imageView = CTImageView() 12 //設置視圖對象的顯示區域 13 imageView.frame = CGRect(x: 0, y: 80, width: 320, height: 280) 14 15 //設置根視圖的背景顏色 16 self.view.backgroundColor = UIColor.black 17 //並將自定義視圖添加到根視圖 18 self.view.addSubview(imageView) 19 } 20 21 override func didReceiveMemoryWarning() { 22 super.didReceiveMemoryWarning() 23 // Dispose of any resources that can be recreated. 24 } 25 }