新書推薦:
《
古今“书画同源”论辨——中国书法与中国绘画的关系问题兼中国画笔墨研究
》
售價:NT$
602.0
《
《日本文学史序说》讲演录
》
售價:NT$
332.0
《
无尽的海洋:美国海事探险与大众文化(1815—1860)
》
售價:NT$
454.0
《
治盗之道:清代盗律的古今之辨
》
售價:NT$
556.0
《
甲骨文丛书·剑桥世界暴力史(第一卷):史前和古代世界(套装全2册)
》
售價:NT$
959.0
《
甲骨文丛书·中华早期帝国:秦汉史的重估
》
售價:NT$
1367.0
《
欲望与家庭小说
》
售價:NT$
449.0
《
惜华年(全两册)
》
售價:NT$
320.0
|
編輯推薦: |
本书采用丰富的实例,直观的代码展示,向读者形象地展现了在创建一款优秀的iOS应用程序时,所需要的大部分知识和技巧。通过对本书的学习,读者可以建立起iOS 10技术的思想框架,并且对iOS 10开发的过程有一个全面的了解,高效地开发出自己的iOS应用程序。
|
內容簡介: |
本书由资深iOS开发工程师精心编撰,系统地介绍了使用iOS 10 Swift 3 Xcode 8开发移动应用的关键技术。 本书共分三篇,*篇为基础篇,主要介绍了iOS开发基础知识,包括iOS系统的历史、Swift 3.0语言、UI界面构建技术、视图控制器、常用的控件、表和集合视图、视图和层、声音、视频、动画等。第二篇为进阶篇,主要介绍了Alamofire网络服务、数据的持久化、多线程、CoreText、CoreImage、Storyboard、自动化测试、性能分析、本地化、加密与安全等实用技术。第三篇为实例篇,通过对实体层、表现层和逻辑层三层相关技术的讲解,向读者详细展示了MVC设计模式在项目开发中的应用方式,并*终创建一个成熟的商业项目。 本书采用丰富的实例,直观的代码展示,向读者形象地讲解了在创建一款优秀的iOS应用程序时,所需要的大部分技巧,帮助读者轻松掌握并高效开发iOS程序。本书适合iOS开发新手、iOS程序员、iPhone开发人员、iPad开发人员使用,也可以作为相关培训机构和大专院校相关专业的教学用书。
|
目錄:
|
目 录
第1章 开发准备 1
1.1 iOS移动开发现状 2
1.1.1 iOS的历史 2
1.1.2 iOS 10的十大变化 4
1.1.3 iOS应用开发的八个特点 5
1.2 iOS 10的新功能 5
1.2.1 SiriKit 6
1.2.2 Proactive Suggestions
(预建议) 6
1.2.3 Integrating with the Messages
App 7
1.2.4 User Notifications 7
1.2.5 Speech Recognition 8
1.2.6 Wide Color 9
1.2.7 Adapting to the True Tone
Display 9
1.2.8 Widget Enhancements 9
1.2.9 Security and Privacy
Enhancements 9
1.3 成为一名iOS开发者 11
1.3.1 硬件上的需求 11
1.3.2 加入Apple开发者计划 11
1.3.3 下载安装Xcode和模拟器 13
1.3.4 创建开发和发布配置文件Provisioning Profile 14
1.4 创建一个基本的iOS项目 17
1.4.1 项目的创建 17
1.4.2 设置项目的信息 19
1.4.3 设置应用的Icon图标 19
1.4.4 设置应用的Launch图片 20
1.4.5 编译并运行项目 22
1.5 iOS应用的生命周期 23
1.5.1 iOS应用程序的状态 24
1.5.2 演示iOS应用程序的各种
状态 25
1.6 小结 26
第2章 Xcode 8 IDE和iOS模拟器 27
2.1 Xcode 8的使用 28
2.1.1 工具栏的使用 28
2.1.2 导航器的功能介绍 29
2.1.3 项目导航器中的内容 30
2.1.4 创建一个组和Swift文件 30
2.1.5 在项目中搜索文件 33
2.1.6 代码的查找和替换 36
2.1.7 代码的Debug调试 36
2.2 iOS模拟器的使用 39
2.2.1 使用多种iOS模拟器 39
2.2.2 iOS模拟器方向的切换 40
2.2.3 iOS模拟器语言的切换 40
2.2.4 截取模拟器屏幕 41
2.2.5 应用程序的退出和删除 41
2.3 小结 42
第3章 Swift 3.0的基础知识 43
3.1 Swift的基本概念 44
3.1.1 Swift语言的特点 44
3.1.2 Swift常量和变量的定义 45
3.1.3 常量和变量的输出 46
3.1.4 注释 47
3.1.5 Playground 47
3.2 数据类型与运算 49
3.2.1 布尔类型 49
3.2.2 Int类型及实例属性 50
3.2.3 浮点类型及实例属性 51
3.2.4 字符和字符串 51
3.2.5 元组类型 54
3.2.6 一元、二元和三元运算符 55
3.2.7 比较运算符 56
3.3 循环语句和条件判断语句 57
3.3.1 for循环 57
3.3.2 while循环语句 58
3.3.3 repeat-while循环语句 59
3.3.4 if条件判断语句 60
3.3.5 switch条件判断语句 60
3.3.6 continue语句和forthrough
语句 61
3.4 数组和字典 62
3.4.1 数组 62
3.4.2 多维数组 64
3.4.3 数组的遍历 65
3.4.4 字典 66
3.5 小结 68
第4章 Swift 3.0的进阶内容 69
4.1 函数 70
4.1.1 函数的定义和调用 70
4.1.2 为参数设置默认值 71
4.1.3 设置可变的函数参数数量 71
4.1.4 函数作为参数和返回类型 72
4.1.5 元组作为函数的返回类型,
实现多个返回值 74
4.1.6 使用函数类型 74
4.1.7 函数的输入输出参数 75
4.1.8 函数的嵌套 76
4.1.9 函数的递归用法 76
4.1.10 常用的内置函数 77
4.2 枚举和结构体 79
4.2.1 枚举 79
4.2.2 结构体 83
4.3 类 85
4.3.1 类的创建 85
4.3.2 类属性的set和get方法 88
4.3.3 类属性的willSet和didSet
方法 89
4.3.4 类的静态方法 90
4.3.5 类的析构 91
4.3.6 类的继承 92
4.3.7 类的延迟加载属性lazy 93
4.3.8 类的引用特征 95
4.3.9 类型检查 95
4.3.10 Any和Anyobject 98
4.4 扩展、协议和其他 99
4.4.1 扩展 99
4.4.2 协议 101
4.4.3 问号?和感叹号! 103
4.5 小结 105
第5章 视图UIView和层CALayer 106
5.1 视图UIView 107
5.1.1 UIView概述 107
5.1.2 UIView的外观属性 109
5.1.3 UIView的几何属性 112
5.1.4 UIView的嵌套和层次关系 114
5.1.5 UIView的交互属性 116
5.1.6 UIView的变形操作 118
5.1.7 自定义UIView视图 120
5.2 CALayer层 124
5.2.1 CALayer边框 124
5.2.2 CALayer阴影 125
5.2.3 CALayer圆角 126
5.2.4 CALayer渐变 127
5.3 小结 129
第6章 视图控制器UIViewController 130
6.1 UIViewController视图控制器概述 131
6.1.1 视图控制器与MVC 131
6.1.2 创建一个视图控制器 132
6.1.3 以模态方式弹出视图控制器 136
6.1.4 视图控制器的生命周期 139
6.1.5 视图控制器和UIScrollView 141
6.2 UITabBarController 145
6.2.1 创建一个UITabBarController 145
6.2.2 改变Tab bar的位置 147
6.2.3 改变UITabBarController
索引 149
6.2.4 在Tab图标上显示角标 149
6.3 UINavigationController 150
6.3.1 创建一个UINavigationController
151
6.3.2 UINavigationController视图
入栈和出栈 153
6.3.3 导航栏和工具栏的显示和
隐藏 157
6.3.4 导航栏样式的修改 157
6.4 导航控制器和标签控制器 158
6.5 小结 161
第7章 常用经典控件 162
7.1 控件概述 163
7.1.1 何为Target-Action机制 163
7.1.2 UIControl类的方法和属性 165
7.1.3 让我们一起动手来实现一个UIControl吧 167
7.2 UIButton的概述 168
7.3 UILabel文本视图 171
7.3.1 UILabel的创建和文案显示 172
7.3.2 UILabel处理过长的文案 173
7.3.3 UILabel的阴影 174
7.4 UISwitch开关视图 175
7.4.1 UISwitch的创建 175
7.4.2 UISwitch的开关使用 176
7.5 UIRefreshControl 刷新控件 176
7.6 UITextField文本框控件 178
7.6.1 UITextField的创建和基本
应用 179
7.6.2 UITextField的背景图 180
7.6.3 UITextField的浮动视图(Overlay view) 181
7.6.4 UITextField的代理UITextFieldDelegate 183
7.7 小结 185
第8章 UITableView和UICollectionView
186
8.1 UITableView概述 187
8.1.1 UITableViewCell单元格 187
8.1.2 创建一个简单的表格 189
8.1.3 自定义单元格UITableViewCell
193
8.1.4 自定义单元格的高度 196
8.1.5 给表格添加章节和索引 198
8.1.6 单元格的选择与取消选择 201
8.1.7 单元格的插入和删除 204
8.1.8 移动单元格的位置 209
8.1.9 表格之间的嵌套 213
8.2 UICollectionView概述 219
8.2.1 UICollectionView的实现
原理 220
8.2.2 创建一个 UICollectionView对象并添加点击事件 221
8.3 小结 225
第9章 触屏事件和触摸手势 226
9.1 触摸事件的监测 227
9.1.1 对触摸事件阶段的监测 227
9.1.2 监测是否触摸到某个视图 229
9.1.3 实现图像视图的拖动 231
9.2 触摸手势的使用 232
9.2.1 实现单点触摸手势 233
9.2.2 实现双击触摸手势 235
9.2.3 实现长按手势的监测 236
9.2.4 捏合手势的监测 238
9.3 3D Touch的使用 239
9.4 小结 242
第10章 动画、声音与视频 243
10.1 制作动画 244
10.1.1 UIView的动画 244
10.1.2 使用UIImageView播放帧
动画 249
10.1.3 位移关键帧动画的制作 251
10.2 音频的播放 254
10.2.1 使用System Sound Services
播放简短声音 255
10.2.2 使用AVAudioPlayer播放
音乐 256
10.3 视频的播放 260
10.3.1 使用AVPlayer播放影片 260
10.3.2 实现影片的画中画功能 262
10.4 小结 265
第11章 Alamofire网络请求框架 266
11.1 Alamofire的前世今生 267
11.1.1 Alamofire的手动集成 267
11.1.2 Alamofire的网络是否联通和
连接方式 269
11.1.3 Alamofire的GET和POST
请求 272
11.1.4 Alamofire的文件上传及
进度显示 274
11.1.5 Alamofire的文件下载及
进度显示 278
11.2 小结 279
第12章 UIWebView与HTML 5技术 280
12.1 UIWebView的使用 281
12.1.1 使用UIWebView加载网页 281
12.1.2 使用UIWebView加载HTML
字符串和GIF动画 283
12.1.3 使用UIWebView加载本地
网页 286
12.1.4 使用Javascript回调原生
程序 289
12.2 创建一个简单的笔记本 292
12.2.1 创建一个可编辑的div 292
12.2.2 设置网页的CSS样式 293
12.2.3 添加插入笔记图片的方法 294
12.2.4 添加删除图片和获得笔记的
方法 295
12.2.5 实现笔记本的用户界面 296
12.3 小结 298
第13章 数据的持久化 299
13.1 解析plist文件 300
13.1.1 创建和解析plist文件 300
13.1.2 将信息写入plist文件 303
13.2 使用CoreData进行数据的持久化 304
13.2.1 创建Core Data实体并插入
数据 306
13.2.2 检索Core Data中的数据 308
13.2.3 修改和删除Core Data数据 310
13.3 小结 312
第14章 多线程技术 313
14.1 多线程的概念 314
14.1.1 任务、进程和线程 314
14.1.2 线程的Stack space 315
14.1.3 线程的优先级 315
14.1.4 线程的生命周期 315
14.1.5 线程和Run loop 316
14.2 使用Thread 316
14.2.1 创建Thread下载图片 317
14.2.2 给Thread加锁使线程同步 319
14.3 Operation技术的使用 322
14.4 Grand Central Dispatch的使用 325
14.4.1 使用GCD查询IP地址
信息 326
14.4.2 DispatchGroup调度组的
使用 328
14.5 小结 329
第15章 MapKit地图 330
15.1 Map Kit的概念 331
15.1.1 MKMapView的显示区域 331
15.1.2 MKMapView的跟踪和
定位 332
15.1.3 MKMapView的交互选项和
装饰物 333
15.1.4 创建一个MKMapView
地图 333
15.1.5 MKMapView代理的使用 335
15.1.6 自定义annotationView和
calloutView 337
15.1.7 Camera相机的使用 341
15.2 小结 342
第16章 iOS的图文混排技术 343
16.1 Core Text的使用 344
16.1.1 文字排版方面的一些基本
概念 344
16.1.2 列出设备中的所有字体 346
16.1.3 富文本的创建 347
16.1.4 图文混排的实现 350
16.2 Text Kit的使用 354
16.2.1 使用Text Kit对文字进行
分栏 354
16.2.2 使用Text Kit制作图文混排
效果 357
16.3 小结 359
第17章 iOS的图像和视频处理技术 360
17.1 Core Image概述 361
17.1.1 使用Core Image的三个类
制作单色调效果 362
17.1.2 使用Core Image给图片添加
马赛克 363
17.1.3 使用Core Image处理视频
画面 364
17.1.4 输出Core Image的所有
滤镜 369
17.1.5 使用CIDetector和CIFeature
进行人脸检测 370
17.2 UIBlurEffect和CGBlendMode 372
17.2.1 使用UIBlurEffect实现毛玻璃
效果 372
17.2.2 使用CGBlendMode实现颜色
混合效果 373
17.3 小结 376
第18章 iOS常用设备的使用 377
18.1 Photos和Camera的使用 378
18.1.1 读取Photos中的图片 378
18.1.2 调用相机拍摄照片 382
18.2 定位设备的使用 384
18.2.1 使用定位设备获取设备地理
位置 385
18.2.2 将地理坐标转换为实际
地名 388
18.3 陀螺仪和加速计设备的使用 390
18.3.1 陀螺仪的原理和应用 390
18.3.2 加速计的原理和应用 390
18.3.3 检测iOS设备的晃动 391
18.4 小结 393
第19章 Storyboard故事板的使用 394
19.1 Storyboard概述 395
19.1.1 Storyboard的优缺点 395
19.1.2 故事板的组织形式 396
19.1.3 创建一个Storyboard 397
19.1.4 更改故事板的初始视图
控制器 398
19.2 在Storyboard中使用标准控件 400
19.2.1 添加三个控件 400
19.2.2 对控件进行连接 402
19.3 在Storyboard中使用表格控件 405
19.3.1 在故事板中添加Table View 405
19.3.2 添加Table View Cell 405
19.3.3 设置Table View的数据源 407
19.3.4 修改ViewController.swift
文件 408
19.4 在Storyboard中使用集合控件 409
19.4.1 添加Collection View 409
19.4.2 设置Collection View Cell 409
19.4.3 设置Collection View的数据源
和代理 411
19.4.4 修改ViewController.swift
文件 412
19.5 Storyboard常见的层次结构 413
19.6 Storyboard之间的页面跳转和参数
传递 417
19.6.1 单个Storyboard中页面间的
参数传递 417
19.6.2 多个Storyboard中的页面跳转
及参数传递 420
19.7 使用约束功能适配多分辨率 424
19.7.1 打开并运行示例项目 424
19.7.2 给父视图MainView添加
约束 426
19.7.3 给三个分隔线添加约束 428
19.7.4 给两个小箭头添加约束 429
19.7.5 给添加新会员按钮添加
约束 431
19.7.6 给无数据图标添加约束 432
19.8 小结 433
第20章 界面测试和自动化测试 434
20.1 单元测试概述 435
20.1.1 Xocde的XCTest框架 435
20.1.2 对其他类的方法进行单元
测试 438
20.1.3 使用XCTest框架进行性能
测试 441
20.2 UI Testing界面测试 442
20.2.1 往项目中插入UI Testing 443
20.2.2 制作UI测试的程序 444
20.2.3 录制UI Testing步骤 446
20.2.4 播放UI Testing的录制
步骤 446
20.3 使用UIAutomation进行自动化
测试 447
20.3.1 使用UIAutomation录制
自动化测试代码 447
20.3.2 测试脚本的保存和加载 449
20.4 小结 449
第21章 iOS应用程序内存泄露的检测 451
21.1 Allocations工具的使用 452
21.2 Leaks工具的使用 458
21.3 小结 461
第22章 iOS应用程序的本地化 462
22.1 应用程序的本地化 463
22.1.1 应用程序名称的本地化 463
22.1.2 应用程序文字内容的本
地化 468
22.1.3 Storyboard的本地化 471
22.1.4 图片素材的本地化 474
22.2 小结 477
第23章 加密与安全 478
23.1 加密与安全 479
23.1.1 对称加密和非对称加密 479
23.1.2 3DES加密 480
23.1.3 SHA1加密 485
23.1.4 MD5加密 487
23.1.5 越狱情况的判断 490
23.2 小结 492
第24章 开源框架CocoaPods 493
24.1 CocoaPods、SPM和Carthage简介 494
24.1.1 为什么使用CocoaPods 494
24.1.2 CocoaPods的安装及淘宝的
镜像使用 495
24.1.3 Podspec的镜像使用 496
24.1.4 CocoaPods的实践 497
24.1.5 pod install 和 pod update 的
使用 497
24.1.6 CocoaPods 的卸载 498
24.2 CocoaPods-app的使用 498
24.2.1 为新项目加入CocoaPods 499
24.2.2 对Podfile的pod install和pod update 500
24.2.3 删除工程中的CocoaPods 501
24.2.4 安装命令行 502
24.3 小结 502
第25章 Git版本控制及GitHub社会化
编程实践 503
25.1 Git前奏曲 504
25.1.1 什么是版本控制 504
25.1.2 版本控制简史 504
25.1.3 Git原理 506
25.1.4 Git的安装、配置、别名和
帮助 508
25.2 Git基础曲 510
25.2.1 创建本地仓库和关联远程
仓库 510
25.2.2 文件在工作区、暂存区和
Git本地仓库中的操作 513
25.2.3 查看提交历史 515
25.2.4 撤销操作 515
25.2.5 标签 516
25.3 小结 519
第26章 项目案例的架构搭建 520
26.1 多人协作的工作流程 521
26.2 技术选型 522
26.3 MVC及工程结构 523
26.4 UITabbarController、UINavigationController和Assets.xcassets的搭建 525
26.4.1 UITabbarController和UINavigationController 525
26.4.2 Assets.xcassets管理 527
26.5 小结 529
第27章 Model层相关框架 530
27.1 XML、Plist、JSON数据格式 531
27.2 开启ATS 532
27.3 AlamofireObjectMapper 533
27.3.1 AlamofireObjectMapper的
安装 533
27.3.2 AlamofireObjectMapper的
使用 533
27.4 ObjectMapper 535
27.4.1 ObjectMapper的安装 535
27.4.2 ObjectMapper中Model与
JSON的转换 536
27.5 Moya 536
27.5.1 Moya的安装 537
27.5.2 Moya的使用 537
27.6 小结 540
第28章 与众平台联姻 541
28.1 ShareSDK 联合登录 542
28.1.1 获取AppKey 542
28.1.2 下载SDK 542
28.1.3 快速集成 542
28.1.4 新建Header File并建立
桥接 543
28.1.5 打开桥接文件(Bridging-Header.h) 544
28.1.6 添加URL Types 546
28.1.7 查看open.qq.com应用的
审核进度 546
28.2 ShareSDK分享 548
28.2.1 增加QQ平台分享支持 548
28.2.2 增加微信平台分享支持 548
28.2.3 QQ和微信平台分享的代码
实现 549
28.3 聚合数据和LeanCloud 550
28.3.1 聚合数据 550
28.3.2 LeanCloud 551
28.4 TalkingData统计 551
28.5 小结 554
第29章 开发SwiftNews新闻客户端
App 555
29.1 SwiftNews App概述 556
29.1.1 修改App Name 556
29.1.2 修改App ICON 557
29.1.3 欢迎页面 558
29.1.4 启动页面 559
29.1.5 Debug模式下的print 561
29.1.6 桥联SVProgressHUD 562
29.1.7 自定义Cell 563
29.1.8 国内和国际新闻模块 564
29.1.9 图片加圆角和助手类 567
29.2 小结 569
第30章 应用程序的打包和发布 570
30.1 iOS应用商店概述 571
30.1.1 App Store的重大更新 571
30.1.2 在iTunes Connect创建一个
App 573
30.1.3 打包App为IPA文件 576
30.1.4 自动化打包App 577
30.1.5 上传App至App Store 580
30.1.6 配置构建版本并提交审核 580
30.2 小结 582
|
內容試閱:
|
前 言 编写本书的目的2011年9月,笔者第一次接触了mac OS平台,并且学习了Xcode工具和Objective-C语言。当时市面上的学习资料也比较稀少,所以学习iOS开发即便是对于笔者这个曾经从事过三年PHP编程和四年J2EE开发的程序员来说,也是比较吃力的事情。而对于现在的读者来说,几乎有数十种iOS入门的教程可供选择。不过令人感到困惑的是,还没有一本书籍,能够作为初学者向更高阶内容前进的桥梁。本书针对没有任何苹果应用程序开发基础的开发者,从基本的iOS程序语言Swift 3.0开始,接着对苹果公司提供的开发API框架Cocoa touch的原理进行分类和详细讲解,进而对iOS的顶尖技术进行梳理和讲解。最后结合实际案例,整合出一款符合MVC设计模式的商业App,让读者能够成为在iOS应用开发领域中驰骋的高手。iOS系统已陪伴我们走过了9个年头,iPhone、iPod touch、iPad这些搭载着iOS系统的设备,以其丰富的功能和出色的用户体验,改变了我们日常的生活、工作和娱乐方式。当全世界都在赞叹苹果的iOS时,iOS的就业大门也面向全世界打开了。随着移动互联网渐入佳境,越来越多的组织和个人开始进入移动互联网领域。在这个充满机会的移动互联时代,赶快加入iOS App的开发行列吧!本书主要内容本书内容全面,几乎涵盖了iOS 10应用开发所需要的主要内容,全书内容言简意赅,讲解方法通俗易懂,特别适合于初学者学习使用。本书共分三篇,第一篇为基础篇,主要介绍了iOS开发基础知识,包括iOS系统的历史、Swift 3.0语言、UI界面构建技术、视图控制器、常用的控件、表和集合视图、视图和层、声音、视频、动画等。第二篇为进阶篇,主要介绍了Alamofire网络服务、数据的持久化、多线程、CoreText、CoreImage、Storyboard、自动化测试、性能分析、本地化、加密与安全等实用技术。第三篇为实例篇,通过对实体层、表现层和逻辑层三层相关技术的讲解,向读者详细展示了MVC设计模式在项目开发中的应用方式,并最终创建一个成熟的商业项目。本书采用丰富的实例,直观的代码展示,向读者形象地讲解了在创建一款优秀的iOS应用程序时,所需要的大部分技巧,帮助读者轻松掌握并高效开发iOS程序。本书特点内容全面:包含Swift 3.0语言、Cocoa Touch、视图控制器、控件、表格、网络、地图、音频、视频、动画、触摸、手势、故事板、CoreData、性能测试、加密解密等众多功能模块。这些内容是iOS开发必知必会的内容,需要读者重点掌握。由浅入深:内容按照原理讲解、实现过程、代码解析的编排顺序讲解,使读者朋友更容易掌握知识点。同时对重点代码做了大量注释和讲解,以便于读者更加轻松地学习。代码精简:为了在有限的篇幅内讲解更多的实用功能,在本书中只给出了每个实例的核心代码及分析结构性代码,保留关键代码和核心代码,以节省篇幅,让本书更超值。原理图解:为复杂的原理讲解配有生动、详细的图例,以帮助读者轻松理解相关概念。重点讲解:对每个实例的核心功能都给予了专门讲解,以便于读者更好地掌握。书中的实例完全适用于全新的iOS 10开发平台,同时也兼容iOS 9开发平台。读者对象通过对本书的学习,读者可以基本建立起iOS 10技术的思想框架,并且对iOS 10开发的过程有一个全面的了解。因此本书适合iOS开发初学者、iOS程序员、iPhone开发人员、iPad开发人员学习,同时也可以作为相关培训机构和大专院校相关专业的教学用书。配套光盘本书配套光盘提供了作者特别录制的有关iOS开发的相关视频课程和全书示例源代码,以方便读者掌握本书内容。源代码中的文件夹名称,如17.1.3 CoreTextProject_RichText,名称的前三个数字依次表示第17章的第1节的第3个示例项目的源代码。CoreTextProject表示当前为CoreText相关的示例项目,而RichText为示例项目的名称。本书中大部分示例可以在Xcode 8的iOS模拟器中运行。部分示例如相机、定位设备的使用,需要连接真机进行测试。此时你需要一个苹果开发者账户,来访问大部分工具和文档,并且需要一个开发人员许可证来在真机上运行应用程序,对此请参考第1章的内容进行账号的注册和设置。勘误和支持书中所有章节的内容和源码,都根据Swift 3.0和iOS 10.0版本进行了更新。如果你遇到有关兼容性的问题请联系我们,我们会发布更新并进行修改。如果你对本书的内容有任何建议,或者发现了本书的一些错误,希望尽快联系我们,这将对本书的后续版本有很大的帮助。我们非常愿意听取任何能使本书变得更加完善的建议,并会不断致力于让本书更加完美。如果你有关于本书的任何评论或者疑问,请访问微信公众号coolketang联系我们。致谢对于本书的完成,要特别感谢王金柱编辑给予的帮助和指导。诸位编辑在检查书稿时认真细致的态度,也令人称赞,整个沟通过程非常愉快。感谢笔者的爱人在孕期依然帮助笔者校对书稿,感谢家里的老大和刚刚出生的小女儿给笔者莫大的精神支持。最后还要感谢冉玉玲、李爱民、谢美仙、李晓飞、朱娟、李红梅、金善众、蔡银珠、金依灵、郑大翰、戴永威等人在写作的过程中给予的支持和鼓励!
编 者 2016年12月12日
视图UIView和层CALayer
窗口和UIView视图是为iOS应用程序构造用户界面的可视化组件。窗口为内容显示提供背景平台,而UIView视图负责绝大部分的内容描画,并负责响应用户的交互。UIView之所以能够显示,完全是因为其内部的CALayer层对象。UIView真正的绘图部分,就由一个CALayer类来管理,其本身更像是一个CALayer的管理器,访问它跟绘图和坐标有关的属性,例如frame、bounds等,实际上内部都是在访问它所包含的CALayer的相关属性。通过操作这个CALayer对象,可以很方便地调整UIView的一些界面属性,比如阴影、圆角大小、边框宽度和颜色等。本章将逐步讲解UIView视图及其内部的CALayer层的原理和具体的使用方法。
5.1 视图UIView5.1.1 UIView概述UIView是UIKit框架里面最基础的视图类。UIView类定义了一个矩形的区域,并管理该矩形区域内的所有屏幕显示。在iOS的应用程序中,每个视图对象都要负责渲染视图矩形区域中的内容,并响应该区域中发生的触碰事件。这一双重行为意味着视图是应用程序与用户交互的重要机制。UIView类定义了视图的基本行为,但并不定义其视觉表现,而是UIKit通过其子类来为文本框、按键及工具条这样的标准界面元素定义具体的外观和行为。UIView视图类如图5.1所示。图5.1这个视图层次可以分为如下几个大类,如表5-1所示。表5-1 UIKit层次图主要项目说明项目 说明NSObject根类 NSObject是一个根类,几乎所有的类都是从它派生而来。根类拥有所有类都有的方法,如alloc和initUIResponsder响应者 UIResponder可以让继承它的类响应移动设备的触摸事件,由于可能有多个对象响应同一个事件,iOS将事件沿响应链向上传递UIWindow窗口类 UIWindow提供了一个用于管理和显示视图的窗口。窗口提供一个描画内容的表面,是所有其他视图的根容器。每个应用程序通常都只有一个窗口UIView视图类 UIView视图是所有控件的父类。控件用于响应用户的交互,而UIVIew则负责内容的显示和布局UIControl控件类 UIControl类几乎是所有交互控件的父类,如按钮,滑块、文本框等。所以UIControl类负责根据触摸事件触发相应的动作警告视图和动作表单 警告视图和动作表单都可以用于提示用户。它们向用户显示一条消息和一个或多个可选的按键,用户通过这些选项来响应消息UIView视图和UIWindow窗口UIView视图和UIWindow窗口是为iOS应用程序构造用户界面的可视组件。窗口为内容显示提供背景平台,而视图负责绝大部分的内容描画与响应用户的交互。iOS程序启动后,创建的第一个视图控件就是UIWindow,接着创建视图控制器的view,并将该view添加到UIWindow上,于是控制器的view就显示在屏幕上了,如图5.2所示。图5.2和桌面mac OS的应用程序有所不同,iOS应用程序通常只有一个窗口,表示为一个UIWindow类的实例。应用程序在启动时创建这个窗口,并往窗口中加入一个或多个视图,然后将它显示出来。窗口一旦显示出来,你基本上就不会再使用到它了,而更多的是对UIView视图的操作。在iOS应用程序中,窗口对象并没有像关闭框或标题栏这样的区域,所以用户不能直接对其进行关闭或其他操作。在mac OS中,NSWindow的父类是NSResponder。而在iOS系统中,UIWindow的父类是UIView。因此,UIWindow窗口在iOS系统中也是一个视图对象。尽管iOS支持多个窗口的存在,但是最好不要创建多个窗口。比如当你希望在自己内容的上方显示警告窗口时,可以使用UIKit提供的警告视图控制器UIAlertController,而不应该再创建新的窗口。5.1.2 UIView的外观属性UIView类的外观属性常用的主要有背景颜色、切边、透明度、显示与隐藏。首先来设置UIView实例的背景颜色。背景颜色backgroundColor1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.89 let view = UIViewframe: CGRectx: 40, y: 80, width: 240, height: 24010 view.backgroundColor = UIColor.black11 self.view.addSubviewview12 }1314 override func didReceiveMemoryWarning {15 super.didReceiveMemoryWarning16 Dispose of any resources that can be recreated.17 }18 }在第9行的代码中,创建了一个位置在40, 80、宽度和高度都是240的UIView视图。关于视图的坐标和尺寸等属性,可参阅5.1.3节中的介绍。接着在第10行代码中,设置视图的backgroundColor背景颜色属性为黑色。UIColor是UIKit中存储颜色信息的一个重要的类,一个UIColor对象包含了颜色和透明度的值,它的颜色空间已经针对iOS进行了优化。UIColor包含了一些类方法用于创建一些最常见的颜色,如白色、黑色、红色、透明色等。最后通过addSubView方法,将设置背景色之后的视图添加到当前视图控制器的根视图中。在将项目编译并运行之后,效果如图5.3所示。除了给视图设置实体颜色之外,还可以将一张图片作为视图的背景颜色:9 let view = UIViewframe: CGRectx: 40, y: 80, width: 240, height: 24010 let image = UIImagenamed: "Sample"11 view.backgroundColor = UIColor.initpatternImage: image!12 self.view.addSubviewview在第10行的代码中,通过UIImage对象加载资源文件夹中的一张图片,然后使用UIColor类的init方法,将加载的图片作为图案平铺在视图的背景中,效果如图5.4所示。不透明度alpha接着对代码继续进行修改,以修改视图的不透明度属性alpha。在第10行的代码中,在视图背景颜色的代码下方,继续添加一行代码,用来设置视图的alpha属性:9 let view = UIViewframe: CGRectx: 40, y: 80, width: 240, height: 24010 view.backgroundColor = UIColor.black11 view.alpha = 0.312 self.view.addSubviewview显示器是由一个个的像素点组成的,每个像素点都可以显示一个由RGBA颜色空间组成的一种颜色值,其中的A就表示透明度alpha。UIView中的alpha属性是一个浮点值,取值范围在0~1.0,表示从完全透明到完全不透明。alpha属性的默认值为1,当把alpha的值设置成0以后:? 当前的UIView及其子视图都会被隐藏,而不管子视图的alpha值为多少。? 当前的UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者。将视图的alpha属性设置为0.3之后,在模拟器中的效果如图5.5所示。隐藏属性hidden视图的hidden属性是布尔值类型,用来表示UIView视图是否处于隐藏的状态。接着修改程序的代码为:9 let view = UIViewframe: CGRectx: 40, y: 80, width: 240, height: 24010 view.isHidden= true11 self.view.addSubviewview在第10行代码中,将视图的isHidden属性设置为true。其默认值为false,即视图处于显示状态。当把值设为true时:? 当前的UIView及其子视图都会被隐藏,而不管子视图的hidden值为多少。? 当前UIView会从响应者链中移除,而响应者链中的下一个会成为第一响应者。在模拟器中的运行结果如图5.6所示。图5.3图5.4图5.5 图5.6切边属性clipsToBounds在默认情况下,当向一个视图中添加一个子视图时,如果子视图的区域超出了父视图的范围,子视图超出的部分仍然会在屏幕上正常显示。如果需要限制子视图的显示范围不超过父视图的显示区域,就需要设置父视图的clipsToBounds属性。首先观察clipsToBounds属性在默认状态下的显示效果:1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let view = UIViewframe: CGRectx: 40, y: 80, width: 240, height: 2409 view.backgroundColor = UIColor.black1011 let subView = UIViewframe: CGRectx: 40, y: 40, width: 240, height: 24012 subView.backgroundColor = UIColor.brown13 view.addSubviewsubView1415 self.view.addSubviewview16 }1718 override func didReceiveMemoryWarning {19 super.didReceiveMemoryWarning20 Dispose of any resources that can be recreated.21 }22 }在第8~9行的代码中,创建了一个UIView视图,并设置视图的背景颜色为黑色。接着在第11~13行的代码中,创建了另一个UIView视图subView,并设置视图的背景颜色为褐色。然后把褐色背景的subView视图添加到view视图中,使subView视图作为黑色背景视图的子视图。最后在第15行的代码中,将view视图添加到当前视图控制器的根视图中。点击Xcode界面左上角的【编译并运行】按钮运行该项目,在模拟器中的效果如图5.7所示。接着在代码中设置view视图的clipsToBounds属性,将该属性的值设置为true:14 view.clipsToBounds = true15 self.view.addSubviewview再次点击编译并运行按钮,运行该项目,在模拟器中的效果如图5.8所示。 图5.7 图5.85.1.3 UIView的几何属性在为你讲解UIView的几何属性之前,首先了解一下iOS系统的坐标系。在iOS坐标系统中,坐标的原点位于左上角。如图5.9所示,我们添加了一个UIImageView视图,其原点在40, 80,宽度为240,高度为340:1 imgView.frame = CGRectx: 40, y: 80, width: 240, height: 340图5.9iOS系统包含两个坐标系,其中UIKit坐标系是X轴正方向向右,Y轴正方向向下,而标准的Quartz 2D绘图坐标系为X轴正方向向右,Y轴正方向向上。下面解释一些相关的概念:? UIView的frameorigin, size属性:定义了一个矩形,描述一个UIView的大小和在父坐标系的位置。? UIView的boundsorigin, size属性:同样定义了一个矩形,描述一个UIView的大小和自身坐标系原点的位置。bounds.origin属性默认值是0, 0,而bounds.size和frame.size是一致的。? UIView的center属性:用于确定一个视图的中心点位置,其参照系也是其父视图的坐标系统。在对视图进行放大、缩小或旋转时,该属性的值不会改变。在下面的代码中,创建了一个简单的UIView,并使用CGRectx, y, width, height来定义视图的坐标和尺寸信息。1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let frame = CGRectx: 0, y: 0, width: 250, height: 2509 let view = UIViewframe: frame10 view.backgroundColor = UIColor.black1112 let subView = UIViewframe: CGRectx: 0, y: 0, width: 200, height: 20013 subView.backgroundColor = UIColor.brown14 view.addSubviewsubView1516 self.view.addSubviewview17 }1819 override func didReceiveMemoryWarning {20 super.didReceiveMemoryWarning21 Dispose of any resources that can be recreated.22 }23 }在第8行的代码中,定义了一个位置在0, 0、宽度和高度都是250的区域。然后在第9~10行的代码中,创建了基于该区域的视图对象,并设置背景颜色为黑色。在第12~14行的代码中,创建了第二个视图对象,并设置背景颜色为褐色。同时将第二个视图作为子视图,添加到第一个视图中。最后在第16行的代码中,将父视图添加到当前视图控制器的根视图中。点击【编译并运行】按钮 ,运行该项目,在模拟器中的效果如图5.10所示。接着来设置父视图view的bounds属性,在第10行的代码的下方添加设置语句:9 let view = UIViewframe: frame10 view.backgroundColor = UIColor.black11 view.bounds = CGRectx: -50, y: -50, width: 250, height: 250完成代码的修改后,再次点击【编译并运行】按钮 运行该项目,在模拟器中的新的效果如图5.11所示。接着继续修改代码,将第11行的代码修改为:9 let view = UIViewframe: frame10 view.backgroundColor = UIColor.black11 view.bounds = CGRectx: -50, y: -50, width: 200, height: 200bounds属性修改后,它的宽度和高度都变小了。再次点击【编译并运行】按钮 ,运行该项目,在模拟器中的新的效果如图5.12所示。图5.10 图5.11 图5.125.1.4 UIView的嵌套和层次关系视图可以通过嵌套的方式,组成复杂的层次结构。例如视图可能包含按钮、标签、图像视图等控件,这些控件则被称为子视图,而包含它们的视图称为父视图。你可以根据项目的业务需求,对视图进行多级嵌套,从而形成复杂的父子视图图层结构。视图的这种布局方式被称为视图层次,一个视图可以包含任意数量的子视图,通过为子视图添加子视图的方式,可以实现任意深度的嵌套。视图在视图层次中的组织方式决定了在屏幕上显示的内容,原因是子视图总是被显示在其父视图的上方;这个组织方法还决定了视图如何响应事件和变化。每个父视图都负责管理其直接的子视图,即根据需要调整它们的位置和尺寸,以及响应它们没有处理的事件。对UIView进行层次管理的方法如表5-2所示。表5-2 UIView视图层次管理方法列表方法名称 方法说明insertSubviewview:, at: 在指定的位置上插入视图insertSubviewview:, aboveSubview: 将视图添加到指定视图的上方insertSubviewview:, belowSubview: 将视图添加到指定视图的下方bringSubviewtoFront: 将指定的子视图移动到最前面bringSubiewtoBack: 将指定的子视图移动到最后面exchangeSubviewat:, withSubviewAt: 交换两个指定位置的子视图在父视图中的位置removeFromSuperview 将子视图从父视图中删除为了演示视图之间的层次转换,我们首先创建三个视图,并将视图依次添加到视图控制器的根视图中。1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let fisrtView = UIViewframe: CGRectx: 20, y: 40, width: 200, height: 2009 fisrtView.backgroundColor = UIColor.black1011 let secondView = UIViewframe: CGRectx: 50, y: 70, width: 200, height: 20012 secondView.backgroundColor = UIColor.darkGray1314 let thirdView = UIViewframe: CGRectx: 80, y: 100, width: 200, height: 20015 thirdView.backgroundColor = UIColor.lightGray1617 self.view.addSubviewfisrtView18 self.view.addSubviewsecondView19 self.view.addSubviewthirdView20 }2122 override func didReceiveMemoryWarning {23 super.didReceiveMemoryWarning24 Dispose of any resources that can be recreated.25 }26 }在第8~15行的代码中,依次创建了三个视图,它们具有相同的尺寸,但是拥有不同的坐标位置和背景颜色。接着在第17~19行的代码中,将创建的三个视图依次添加到当前视图控制器的根视图中。点击【编译并运行】按钮 ,运行该项目,在模拟器中的效果如图5.13所示。观察模拟器中的三个视图的层次关系,然后使用insertSubviewview, belowSubview方法,调整thirdView和secondView两个视图在父视图中的层次:17 self.view.addSubviewfisrtView18 self.view.addSubviewsecondView19 self.view.addSubviewthirdView20 self.view.insertSubviewthirdView, belowSubview: secondView通过在第20行的代码中调用insertSubview方法,将第三个视图插入到第二个视图的下方,最终效果如图5.14所示。继续修改代码,在第20行的代码下方添加一行代码,调用bringSubviewtoFront:方法,将第一个视图放置在所有子视图的上方:20 self.view.insertSubviewthirdView, belowSubview: secondView21 self.view.bringSubviewToFrontfisrtView通过在第21行调用bringSubviewtoFront:方法,第一个视图被放置在其父视图的最顶部的位置,如图5.15所示。最后再次修改代码,在第21行的代码下方添加一行代码,调用removeFromSuperview方法,将第一个视图从其父视图中删除:21 self.view.bringSubviewtoFront: fisrtView22 fisrtView.removeFromSuperview通过调用firstView视图的removeFromSuperview方法,firstView视图将从父视图中移除,效果如图5.16所示。 图5.13图5.14 图5.15图5.165.1.5 UIView的交互属性通过设置UIView的userInteractionEnabled属性,可以激活用户的交互特性。该属性值为布尔类型,由属性本身的名称可知,该属性决定UIView是否接受并响应用户的交互。当该属性的值为false时,UIView会忽略那些发生在其自身的诸如触摸和键盘等用户事件,并将这些事件从消息队列中移除出去;当值为true时,这些用户事件会正常派发至UIView本身,UIView会按照之前注册的事件处理方法来响应这些事件。下面通过一个实例,讲解如何给视图添加交互事件。1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.89 let touchView = UIViewframe: CGRectx: 60, y: 60, width: 200, height: 20010 touchView.backgroundColor = UIColor.black11 self.view.addSubviewtouchView1213 let guesture = UITapGestureRecognizertarget: self, action: #selectorViewController.SingleTap14 touchView.addGestureRecognizerguesture15 }1617 func SingleTap18 {19 print"You touched me."20 }2122 override func didReceiveMemoryWarning {23 super.didReceiveMemoryWarning24 Dispose of any resources that can be recreated.25 }26 }在第9~11行的代码中,创建了一个简单的黑色背景的UIView视图,并将视图添加到当前视图控制器的根视图。接着在第13行的代码中,创建了一个UITapGestureRecognizer手势对象,手势对象的详细讲解可参考第9章课程。手势创建完成后,在第14行的代码中,通过addGestureRecognizer方法,将手势对象指定给视图对象。当用户点击该视图时,将调用手势定义的回调方法SingleTap。最后在第17~20行的代码中,实现手势的回调方法SingleTap,当用户点击手势绑定的视图时,将在控制台输出一条日志语句。完成代码的编写之后,点击【编译并运行】按钮 ,运行该项目,项目在模拟器中的效果如图5.17所示。在模拟器中点击黑色的视图对象,并观察Xcode界面的右下角控制台的日志输出。5.1.6 UIView的变形操作CGAffineTransform仿射转换结构体代表了一种用于仿射变换的矩阵。结构体的参数指定了从一个坐标系的点转化成另外一个坐标系的点的规则。你可以通过仿射转换功能,对一个视图的坐标系统进行一些变换,从而实现视图的缩放、旋转、位移等功能。仿射变换是一种特殊类型的映射,保留在一个路径中的平行线,但不一定保留长度或角度。缩放、旋转、平移是最常用的仿射变换。我们通常不会直接创建一个仿射变换,只需要根据现有的参数,修改现有的仿射变换即可。常用的几种仿射变换见表5-3所示。表5-3 几种常用的仿射变换名称 说明CGAffineTransformMakeTranslation 通过指定的x, y值,创建一个平移矩阵CGAffineTransformTranslate 对已存在的矩阵进行平移CGAffineTransformMakeRotation 通过指定角度来创建一个旋转矩阵CGAffineTransformRotate 对已存在的矩阵进行旋转CGAffineTransformMakeScale 通过指定的x, y缩放因子,创建一个缩放矩阵CGAffineTransformScale 对已存在的矩阵进行缩放CGAffineTransformInvert 反转矩阵,将值与反转矩阵相乘得到原先的值CGAffineTransformConcat 对仿射效果进行叠加操作平移仿射变换接着我们来编写代码,使用仿射变换对视图进行位移、缩放、放置和斜切的变换操作。1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let view = UIViewframe: CGRectx: 0, y: 0, width: 200, height: 509 view.center = self.view.center10 view.backgroundColor = UIColor.black11 self.view.addSubviewview1213 let transform = view.transform14 view.transform = transform.translateByx: 0, y: 10015 }1617 override func didReceiveMemoryWarning {18 super.didReceiveMemoryWarning19 Dispose of any resources that can be recreated.20 }21 }在第8~9行的代码中,创建了一个位于{0, 0}、宽度为200、高度为50的UIView视图。接着设置视图的center属性,将视图的center属性设置为与当前视图控制器根视图的center相同的位置。由于仿射变换是以视图的center为基点的,所以将视图放置在屏幕的中心位置,方便对仿射变换操作效果进行观察。在第10~11行的代码中,将视图的背景颜色设置为黑色,并添加到当前视图控制器的根视图中。该视图在未使用仿射变换前的效果,如图5.18所示。在第13~14行的代码中,首先获得视图对象的transform属性,然后使用仿射变换的transform.translateByx:, y:方法,对视图的仿射矩阵进行平移操作。其中transform表示现有的矩阵,参数x表示在水平方向上平移的距离,参数y表示在垂直方向上平移的距离。这里是在垂直方向上,将视图的矩阵向下平移了100。点击【编译并运行】按钮 ,运行该项目,项目在模拟器中的效果如图5.19所示。缩放仿射变换接着来使用transform.scaleByx: , y: 方法,对视图的矩阵进行缩放操作。其中transform表示现有的矩阵,参数x表示在水平方向上缩放的比例,参数y表示在垂直方向上缩放的比例。将第14行的代码修改为:14 view.transform =transform.scaleByx: 1.5, y: 1.5对矩阵的缩放操作,本质上是拉长或缩短原来矩阵中的点与点之间的距离。这里是通过transform对象的scaleByx: , y: 方法,将视图在水平和垂直方向上各放大了1.5倍。最终的效果如图5.20所示,同时与图5.18的原始效果进行比较。旋转仿射变换接着来使用transform.rotateangle方法,对视图的矩阵进行旋转操作。其中transform表示现有的矩阵,参数angle表示在顺时针方向上旋转的角度。14view.transform = transform.rotate3.144这里通过transform的rotateangle方法,将视图沿顺时针旋转45度,最终效果如图5.21所示。斜切仿射变换在上面进行的平移、缩放、旋转操作中,都是采用系统封装好的方法。例如我们使用transform的rotateangle方法传入的angle参数,就是对CGAffineTransformMake方法的6个参数的封装。系统并没有提供类似于CGAffineTransformRotate方法的斜切操作方法。所以这里我们将使用CGAffineTransformMakeCGFloat sx, CGFloat shx, CGFloat shy, CGFloat sy, CGFloat tx, CGFloat ty方法,自定义视图的变换,从而实现对视图进行斜切操作。CGAffineTransformMake方法中的6个参数的含义如表5-4所示。表5-4 CGAffineTransformMake方法参数列表参数名称 参数说明 参数名称 参数说明sx 水平方向上的缩放因子 shy 垂直方向上的斜切因子sy 垂直方向上的缩放因子 tx 水平方向上的位移因子shx 水平方向上的斜切因子 ty 垂直方向上的位移因子在Swift 3.0中,CGAffineTransformMake方法已经被取消,但是CGAffineTransform包含6个属性a、b、c、d、tx、ty,分别对应于CGAffineTransformMake方法的sx、shx、shy、sy、tx、ty 6个参数,因此我们可以通过设置这6个参数的值,来达成和使用CGAffineTransformMake方法一样的效果。这里将第14行的代码修改为:14 view.transform.a = 1.015 view.transform.b = 0.516 view.transform.c = 0.517 view.transform.d = 1.018 view.transform.tx = 0.019 view.transform.ty = 0.0在设置transform的过程中,其参数a、d的值为1,即保持缩放比例不变;其tx、ty属性为0,即在水平和垂直方向上不进行平移;其b和c属性都为0.5,即在水平和垂直方向上进行斜切操作。斜切的效果如图5.22所示。 图5.18 图5.19 图5.20 图5.21 图5.225.1.7 自定义UIView视图在iOS开发工作中,经常会使用到自定义的UIView视图。使用自定义视图,可以很方便地复用一些复杂或不规则的视图对象。在创建自定义UIView视图前,首先往项目中添加一个Swift文件,如图5.23所示。接着在弹出的模板选择窗口中,依次选择【iOS Source Swift File】选项,创建一个新的Swift类文件,如图5.24所示。图5.23图5.24Swift文件创建后的效果如图5.25所示。图5.25编写RoundView自定义视图现在开始编写代码,实现RoundView.swfit自定义视图。1 import UIKit2 class RoundView: UIView3 {4 var color = UIColor.blue5 override initframe: CGRect6 {7 super.initframe:frame8 self.backgroundColor = UIColor.clear9 }1011 override func draw_ rect: CGRect12 {13 let ctx = UIGraphicsGetCurrentContext14 ctx?.clearself.frame15 ctx?.setFillColorcolor.cgColor16 ctx?.fillEllipsein: CGRectx: 0, y: 0, width: self.frame.width, height: self.frame.height17 }1819 required init?coder aDecoder: NSCoder20 {21 fatalError"initcoder: has not been implemented"22 }23 }在第2行的代码中,使用class关键字,创建了一个名为RoundView的类,该类继承自UIView父类。RoundView类的主体功能被放置在一对大括号之间。在第4行的代码中,给RoundView类添加了一个UIColor类型的属性color,并设置color属性的默认值为蓝色。接着在第5~9行的代码中,重写了RoundView自定义类的初始化init方法。在该初始化方法中,首先调用父类的初始化方法,然后自定义设置背景颜色为无色,从而保证RoundView只显示在drawRect方法中创建的内容。在第11~17行的代码中,重写了drawRect方法。绘制一个UIVIew最灵活的方式就是由它自己完成绘制。实际上你并没有绘制一个UIView,而只是子类化了UIView,并赋予子类绘制自己的能力。当一个UIVIew需要执行绘图操作时,drawRect:方法就会被调用。覆盖此方法可让你获得绘图操作的机会。当drawRect:方法被调用时,当前的图形上下文也被设置为属于视图的图形上下文,可以使用Core Graphics或UIKit提供的方法将图形画到该上下文中。所以在第13行的代码中,通过UIGraphicsGetCurrentContext方法,获得当前的图形上下文。然后调用ctx上下文的clear方法擦除一个区域,这个函数会擦除一个矩形范围内的所有已存在的绘图内容。接着调用ctx上下文的setFillColor方法,设置在图形上下文中的填充颜色为当前视图属性color的颜色。最后在第16行的代码中,调用ctx上下文的fillEllipse方法,在当前的图形上下文中,在0,0位置绘制与当前视图相同尺寸的椭圆。当视图的宽度和高度相同时,绘制的图形为正圆。使用自定义视图完成自定义视图的创建后,打开ViewController.swift文件,在此文件中创建刚刚自定义的视图,并将自定义视图添加到当前的视图控制器的根视图中。1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.89 let view = RoundViewframe: CGRectx: 40, y: 40, width: 240, height: 24010 self.view.addSubviewview11 }1213 override func didReceiveMemoryWarning {14 super.didReceiveMemoryWarning15 Dispose of any resources that can be recreated.16 }17 }在第9行的代码中,创建了一个自定义的RoundView视图,其位置在40, 40,宽度和高度都是240。接着在第10行的代码中,将视图添加到当前视图控制器的根视图中。接着点击【编译并运行】按钮 ,运行该项目。项目在模拟器中的效果如图5.26所示。由于我们给RoundView自定义视图添加了color属性,所以你可以自定义圆形的颜色。在第9行的代码下方添加一行代码,将圆形的背景颜色修改为绿色:10 view.color = UIColor.green修改后的效果如图5.27所示。接着我们再修改第9行的代码,将自定义视图的高度设置为140:9 let view = RoundViewframe: CGRectMake40, 40, 240, 140自定义视图的高度变小后,将由正圆转换为椭圆,如图5.28所示。图5.26 图5.27 图5.285.2 CALayer层UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它,它本身完全是由CoreAnimation来实现的。而UIView真正的绘图部分,是由一个叫CALayerCore Animation Layer的类来管理的。UIView本身更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等,实际上内部都是在访问它所包含的CALayer的相关属性。UIView与CALayer的关系如图5.29所示。图5.295.2.1 CALayer边框通过设置CALayer的borderWidth和borderColor属性,可以给视图添加边框效果:1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let view = UIViewframe: CGRectx: 60, y: 60, width: 200, height: 2009 view.backgroundColor = UIColor.black10 view.layer.borderWidth = 2011 view.layer.borderColor = UIColor.lightGray.cgColor1213 self.view.addSubviewview14 }1516 override func didReceiveMemoryWarning {17 super.didReceiveMemoryWarning18 Dispose of any resources that can be recreated.19 }20 }在第8~9行的代码中,创建了一个位于60,60、宽度和高度都是200的视图,并设置视图的背景颜色为黑色。接着在第10行的代码中,设置层的边缘宽度borderWidth为20。然后在第11行的代码中,设置层的边缘颜色borderColor的值为浅灰色。这里使用的是CGColorRef数据类型,而不是UIColor。这是因为UIColor是定义在UIKit框架中的,只能在iOS中使用。而CALayer是定义在QuartzCore框架中的,所以需要使用具有跨平台特性的CGColorRef数据类型。通过调用UIColor对象的CGColor属性,可以获得UIColor转换后的CGColorRef值。接着点击Xcode界面左上角的【编译并运行】按钮,运行该项目。项目在模拟器中的效果如图5.30所示。5.2.2 CALayer阴影通过设置CALayer的几个阴影属性,可以给视图添加阴影效果,这样即使不需要使用Photoshop等图像处理软件,也能够实现投影效果了。1 class ViewController: UIViewController {23 override func viewDidLoad {4 super.viewDidLoad5 Do any additional setup after loading the view, typically from a nib.6 let view = UIViewframe: CGRectx: 60, y: 60, width: 200, height: 2007 view.backgroundColor = UIColor.black89 view.layer.shadowColor = UIColor.black.cgColor10 view.layer.shadowOffset = CGSizewidth: 10.0, height: 10.011 view.layer.shadowOpacity = 0.4512 view.layer.shadowRadius = 5.01314 self.view.addSubviewview15 }1617 override func didReceiveMemoryWarning {18 super.didReceiveMemoryWarning19 Dispose of any resources that can be recreated.20 }21 }在第8~9行的代码中,创建了一个位于60,60、宽度和高度都是200的视图,并设置视图的背景颜色为黑色。接着在第9~12行的代码中,设置了层的阴影属性。首先在第9行的代码中,设置了shadowColor阴影颜色为黑色。然后在第10行的代码中,设置阴影的偏移值为10.0, 10.0,即在水平方向上向右侧偏移10,在垂直方向上向下偏移10。shadowOffset的默认值为0.0, -3.0。在第11行的代码中,设置阴影的不透明度值为0.45。该属性的取值范围为0~1,即从完全透明到完全不透明。shadowOpacity的默认值为0.0。最后在第12行的代码中,设置阴影的shadowRadius模糊半径为5.0,用来实现阴影的模糊效果,使阴影更加柔和、自然。shadowRadius参数的默认值为3.0。接着点击Xcode界面左上角的【编译并运行】按钮 ,运行该项目。项目在模拟器中的效果如图5.31所示。5.2.3 CALayer圆角通过设置CALayer的cornerRadius属性,可以给视图添加圆角效果:1 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let view = UIViewframe: CGRectx: 60, y: 60, width: 200, height: 2009 view.backgroundColor = UIColor.black10 view.layer.cornerRadius = 401112 let subView = UIViewframe: CGRectx: 0, y: 0, width: 200, height: 10013 subView.backgroundColor = UIColor.gray1415 view.addSubviewsubView16 self.view.addSubviewview17 }1819 override func didReceiveMemoryWarning {20 super.didReceiveMemoryWarning21 Dispose of any resources that can be recreated.22 }23 }在第8~9行的代码中,创建了一个位于60,60、宽度和高度都是200的视图,并设置视图的背景颜色为黑色。接着在第10行的代码中,设置层的cornerRadius圆角半径为40。当该属性被设置为大于0的值时,将会在层的四周绘制指定半径的圆角。在第12~13行的代码中,创建了一个宽度为200、高度为100、位于0, 0的视图,该视图的背景颜色为灰色。最后在第15~16行的代码中,将灰色视图作为子视图,添加到黑色视图之中。并将黑色视图添加到当前视图控制器的根视图中。接着点击Xcode界面左上角的【编译并运行】按钮 ,运行该项目。项目在模拟器中的效果如图5.32所示。从模拟器中的效果可以看出,虽然给黑色视图添加了圆角效果,但是由于子视图的存在,你无法看到上方两个顶点的圆角效果。这是因为圆角效果只对视图的背景颜色和层的边框起作用,而不会对层中的内容起作用。不过系统提供了一个属性masksToBounds,你可以将该属性的值设置为true,这样将会沿着圆角边缘对视图中的内容进行裁切。在第10行的代码的下方添加一行新的代码:8 let view = UIViewframe: CGRectMake60, 60, 200, 2009 view.backgroundColor = UIColor.blackColor10 view.layer.cornerRadius = 4011 view.layer.masksToBounds = true设置层的masksToBounds属性之后,再次运行模拟器,视图的圆角效果如图5.33所示。在设置圆角半径时,如果将cornerRadius设置为正方形宽度的一半,那么将会创建了一个正圆形。这里将第10行的代码修改为:10 view.layer.cornerRadius = 100修改cornerRadius半径数值后的效果如图5.34所示。也许你还想知道,如果继续增加cornerRadius半径数值,会有什么样的圆角效果。我们将cornerRadius半径数值设置为与正方形宽度相同:11 view.layer.cornerRadius = 200将cornerRadius半径数值修改为200后的效果如图5.35所示。5.2.4 CALayer渐变CALayer和UIView相似地方是,CALayer层也可以嵌套多个子CALayer层,从而实现多种多样的效果。这里将演示如何往层中添加一个CAGradientLayer渐变层。CAGradientLayer是用来生成两种或更多的颜色平滑渐变效果的。图5.32图5.33 图5.34 图5.351 import UIKit23 class ViewController: UIViewController {45 override func viewDidLoad {6 super.viewDidLoad7 Do any additional setup after loading the view, typically from a nib.8 let rect = CGRectx: 20, y: 60, width: 240, height: 2409 let gradientView = UIViewframe: rect1011 let gradientLayer = CAGradientLayer12 gradientLayer.frame = gradientView.frame1314 let fromColor = UIColor.yellow.cgColor15 let midColor = UIColor.blue.cgColor16 let toColor = UIColor.red.cgColor1718 gradientLayer.colors = [fromColor, midColor, toColor]19 gradientLayer.startPoint = CGPointx: 0, y: 020 gradientLayer.endPoint = CGPointx: 1, y: 121 gradientLayer.locations = [0, 0.3, 1]2223 gradientView.layer.addSublayergradientLayer24 self.view.addSubviewgradientView25 }2627 override func didReceiveMemoryWarning {28 super.didReceiveMemoryWarning29 Dispose of any resources that can be recreated.30 }31 }在第8~9行的代码中,创建了一个位于20,60、宽度和高度都是240的视图。接着在第11~12行的代码中,创建一个CAGradientLayer渐变层,并设置渐变层的frame属性与视图的frame属性相同。然后在第14~16行的代码中,依次创建三个颜色:黄色、蓝色和红色。这三个颜色将作为渐变线上的起始颜色、中间颜色和结束颜色。在第18行的代码中,设置了渐变层的colors属性,这里将刚刚创建的三个颜色放在一个数组中,并赋予colors属性。在第19行的代码中,设置了渐变层的起点位置为0, 0,即渐变线的起点位于渐变层的左上角。接着在第20行的代码中,设置了渐变层的终点位置为1, 1,即渐变线的终点位于渐变层的右下角。这样就创建了一个从左上角至右下角45度方向的渐变效果。在第21行的代码中,设置了渐变层的各颜色点在颜色线中的分布情况。在locations属性值数组中的0.3表示渐变线中间的颜色,即蓝色将位于渐变线30%的位置。在第23~24行的代码中,依次将渐变图层添加到视图对象的根层中,然后将视图对象添加到当前视图控制器的根视图中。接着点击Xcode界面左上角的【编译并运行】按钮 ,运行该项目。项目在模拟器中的效果如图5.36所示。从图中的效果可以看出,我们创建了一条从左上角至右下角的渐变效果,渐变色依次为黄色、蓝色、红色。其中蓝色位于渐变线30%的位置,即比较靠近渐变线开始位置的黄色,而距离渐变线结束位置的红色较远。5.3 小 结我们经常会在网上冲浪,网页中的各种视觉元素基本上都是由Div容器组成的。就像网页中的Div标签一样,iOS设备中的大部分视觉元素也都是通过UIView视图组成的。本章主要讲解了UIView视图的基本属性、各个属性之间的关系,以及如何在应用程序中创建和操作这些属性。除此之外,本章还讨论了视图如何响应触摸事件,以及如何创建自定义视图以描绘定制的内容。使用UIView甚至可以制作出很多精美的动画效果,我们将在第10章详细讨论UIView动画的设计和制作。在讲解UIView视图时,始终绕不开CALayer层概念,所以在本章还讲解了CALayer层和UIView视图之间的联系,以及如何使用CALayer构建一些诸如圆角、阴影、渐变之类的外观效果。
|
|