[Swift通天遁地]八、媒体与动画-(13)CoreText框架实现图文混排

本文将演示CoreText框架实现图文混排。CoreText(富文本)框架并不支持图片的绘制,

需要借助Core Graphics框架来进行图片的绘制。

图文混排的实现原理非常简单,就是在一个富文本中插入一个占位符,

表示此处需要插入一张图片。然后再由另一个图形绘制框架,

在占位符所在位置绘制指定的图片。

在项目文件夹上点击鼠标右键,弹出右键菜单。

【New File】->【Cocoa Touch】->【Next】->

【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 }

原文地址:https://www.cnblogs.com/strengthen/p/10354875.html

时间: 2024-11-07 18:35:19

[Swift通天遁地]八、媒体与动画-(13)CoreText框架实现图文混排的相关文章

[Swift通天遁地]八、媒体与动画-(15)使用TextKit实现精美的图文混排效果

本文将演示制作一款更加精美的图文的图文混排效果:将文字紧贴图片边缘的图文混排效果. 往项目中导入一份文本文件. 在左侧的项目导航区,打开视图控制器的代码文件[ViewController.swift] 1 import UIKit 2 3 class ViewController: UIViewController { 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 // Do any additional setup afte

[Swift通天遁地]八、媒体与动画-(6)使用开源类库快速实现滑入动画

本文将演示使用第三方类库,快速实现一个从上向下滑入的动画. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, '12.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'Spring', :git => 'https://github.com/MengTo/Spring.git' 7 e

[Swift通天遁地]八、媒体与动画-(8)使用开源类库快速实现位移动画

本文将演示使用第三方类库,快速实现位移动画. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, '8.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'Cheetah' 7 end 根据配置文件中的相关设置,安装第三方类库. 安装完成之后,双击打开项目文件[DemoApp.xcodep

[Swift通天遁地]八、媒体与动画-(7)实现多个动画的顺序播放效果

本文将演示使用第三方类库,实现多个动画的顺序播放效果. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, '12.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'Spring', :git => 'https://github.com/MengTo/Spring.git' 7 end

[Swift通天遁地]八、媒体与动画-(9)快速实现复合、Label、延续、延时、重复、缓冲、弹性动画

本文将演示多种动画类型效果. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, '8.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'Cheetah' 7 end 根据配置文件中的相关设置,安装第三方类库. 安装完成之后,双击打开项目文件[DemoApp.xcodeproj] 在左侧

[Swift通天遁地]八、媒体与动画-(10)在项目中播放GIF动画

本文将演示使用第三方类库播放GIF动画. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, '12.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'SwiftGifOrigin', '~> 1.6.1' 7 end 根据配置文件中的相关设置,安装第三方类库. 安装完成之后,双击打开项

[Swift通天遁地]八、媒体与动画-(11)实现音乐播放的动态视觉效果

本文将演示使用第三方类库实现音乐播放的动态视觉效果. 首先确保已经安装了所需的第三方类库.双击查看安装配置文件[Podfile] 1 platform :ios, ‘12.0’ 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'AudioIndicatorBars' 7 end 根据配置文件中的相关设置,安装第三方类库. 安装完成之后,双击打开项目文

[Swift通天遁地]八、媒体与动画-(1)实现音频的播放和停止

本文将演示实现对音频播放的控制. 首先确保在项目中,已经安装了所需的第三方类库,点击查看安装的配置文件. 1 platform :ios, '8.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'CryptoSwift', :git => "https://github.com/krzyzanowskim/CryptoSwift"

[Swift通天遁地]八、媒体与动画-(3)实现视频播放的水印、Overlay、暂停时插入广告等效果

本文将演示使用第三方类库实现视频视频播放的水印.Overlay.暂停时插入广告等效果. 首先确保在项目中,已经安装了所需的第三方类库,点击查看安装的配置文件. 1 platform :ios, '8.0' 2 use_frameworks! 3 4 target 'DemoApp' do 5 source 'https://github.com/CocoaPods/Specs.git' 6 pod 'MobilePlayer' 7 end 根据配置文件中的相关设置,安装第三方类库. 完成安装之后