Add files via upload

This commit is contained in:
Yurk
2021-11-01 19:00:11 +08:00
committed by GitHub
parent a06da6efdd
commit 9b67ef3267
75 changed files with 1299 additions and 0 deletions

View File

@@ -0,0 +1,182 @@
# Cocopods的安装与使用
## Cocopods介绍
CocoaPods是管理iOS项目所依赖的第三方开源库的工具其项目源码在Github上管理。若项目开发不使用Cocopods我们引入第三方开源库要做的步骤可能有
- 把开源库的源代码复制到项目中
- 添加一些依赖框架和动态库(可能还需要引入其他的第三方开源库)
- 设置-ObjC-fno-objc-arc 等参数
- 管理他们的更新
CocoaPods 是管理第三方插件的合集,其出现帮助节省了配置和更新第三方开源库的时间。 CocoaPods 将所有依赖的库都放在一个名为 Pods 的项目下,然后让主项目依赖 Pods 项目。然后, 我们编码工作都从主项目转移到 Pods 项目。Pods 项目最终会编译为一个 libPod-项目名.a 静态库, 主项目依赖于这个静态库。对于资源文件CocoaPods 提供了一个名为 Pods-resources.sh 的 bash 脚本,该脚本在每次项目编译的时候都会执行,将第三方库的各种资源文件复制到目标目录中。
CocoaPods 通过一个名为 Pods.xcconfig 的文件来在编译时设置所有的依赖和参数。
CocoaPods 是用 Ruby 写的,并由若干个 Ruby 包 (gems) 构成的。在解析整合过程中,最重 要的几个 gems 分别是:CocoaPods/CocoaPods, CocoaPods/Core, 和 CocoaPods/Xcodeproj。
## Cocopods安装
在使用 Cocopods 之前,我们需要在`Terminal`进行安装:
1. 安装需要用到 Ruby虽然 Mac 自带了 Ruby但版本需要更新
```bash
sudo gem update system
```
2. 输入密码后安装 Cocopods
```bash
sudo gem install cocoapods
```
3. 如果安装过程过慢导致失败,可以更换国内下载源,安装完成后,在 `Terminal` 中:
- cd 到目标工程文件路径下
- pod init 会看到 Podfile 文件
- vim Podfile 即可向其中插入想引用的第三方库
## 示例:安装第三方库
本部分我们将安装
新建Xcode项目myFirstApp后关闭Xcode过程可参考Task00中的第一部分教程打开终端command+ "空格"
1. cd到目标目录下
```bash
cd Downloads/code/myFirstApp/
```
2. 进行Cocopods初始化
```bash
pod init
```
3. 打开Podfile文件
```bash
open Podfile
```
![1](img/1.png)
4. 插入如下命令后关闭Podfile
```bash
pod 'Charts'
pod 'TinyConstraints'
```
![2](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/2.png)
5. 返回`终端`Terminal进行Pod更新等待片刻即可
```bash
pod update
```
6. 在目录下双击运行 `myFirstApp.xcworkspace`
![截屏2021-10-26 下午10.02.02](/Users/mac/Library/Application Support/typora-user-images/截屏2021-10-26 下午10.02.02.png)
7. 在`myFirstApp`-`myFirstApp`-`ViewController.swift`导入加载的两个第三方库
```swift
import Charts
import TinyConstraints
```
![3](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/3.png)
8. 即可完成加载,完整代码如下(暂时无需弄懂代码含义,复制即可):
```swift
import UIKit
import Charts
import TinyConstraints
class ViewController: UIViewController,ChartViewDelegate {
lazy var lineChartView:LineChartView={
let chartView = LineChartView()
chartView.backgroundColor = .systemGray6
chartView.rightAxis.enabled = false
let yAxis = chartView.leftAxis
yAxis.labelFont = .boldSystemFont(ofSize: 12)
yAxis.setLabelCount(6, force: false)
yAxis.labelTextColor = .black
yAxis.labelPosition = .outsideChart
chartView.xAxis.labelPosition = .bottom
chartView.xAxis.labelFont = .boldSystemFont(ofSize: 12)
chartView.xAxis.setLabelCount(6, force: false)
chartView.xAxis.labelTextColor = .black
chartView.xAxis.axisLineColor = .systemGray
chartView.animate(xAxisDuration: 4.5)
return chartView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(lineChartView)
lineChartView.centerInSuperview()
lineChartView.width(to:view)
lineChartView.heightToWidth(of:view)
setData()
}
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
print(entry)
}
func setData(){
let set1 = LineChartDataSet(entries: yValues, label: "Subscribers")
let data = LineChartData(dataSet:set1)
lineChartView.data = data
}
let yValues:[ChartDataEntry] = [
ChartDataEntry(x:0.0, y:10.0),
ChartDataEntry(x:1.0, y:9.0),
ChartDataEntry(x:2.0, y:8.0),
ChartDataEntry(x:3.0, y:7.0),
ChartDataEntry(x:4.0, y:6.0),
ChartDataEntry(x:5.0, y:5.0),
ChartDataEntry(x:6.0, y:4.0),
ChartDataEntry(x:7.0, y:3.0),
ChartDataEntry(x:8.0, y:2.0),
ChartDataEntry(x:9.0, y:1.0)
]
}
```
9. 点击运行,预览状态如下:
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/4.png" alt="4" style="zoom:50%;" />
## 如何寻找自己心仪的第三方库?
如何找到`Charts`与`TinyConstraints`等优秀的第三方库如何知晓不同的第三方库的安装命令你可以访问Github的开源项目
[awesome-ios](https://github.com/vsouza/awesome-ios)
这里面罗列了iOS开发流程中可能用到的第三方库以`Charts`为例我们点击相应label进行跳转
![5](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/5.png)
就会得到安装该库的命令:
![6](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/6.png)
至此我们已经学会了基本的第三方库引入下面我们要学习基本控件的应用以更好地运用到我们的app上

View File

@@ -0,0 +1,217 @@
# ScrollView的应用
## 什么是ScrollView
`ScrollView`(即滚动视图)可被应用到多种场景,例如:纵向滚动视图可以用来上下滑动以查看超出屏幕尺寸的内容,横向滚动视图可以用来实现翻页、轮播图等功能。事实上, 对某个图片的缩放、移动等功能也是由ScrollView 来实现的。在本章中,你将学会如何开启计时器,如何纵向、横向滚动查看页面,如何滑动查看图片以及实现轮播图等。
## Storyboard中添加Scroll View
在storyboard控件库中搜索`Scroll View`,并拖拽至面板中,放大到与屏幕同尺寸。
![scroll View](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/scroll View.png)
右侧属性栏中Indicators部分罗列了两种滚动条`纵向滚动``横向滚动`,如果我们不想在滑动过程中显示这两种滚动条,取消勾选即可。
## ScrollView 的代理及基本属性
`Main.storyboard` 中添加了 ScrollView 之后,我们需要手动在 `UIViewController` 中代理`UIScrollViewDelegate`,实现步骤如下:
1. 打开`Main.Storyboard`,鼠标右键将`ScrollView`控件与`ViewController`面板相连,点击`delegate`
![sc1](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/sc1.png)
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/sc delegate.png" alt="sc delegate" style="zoom:50%;" />
2. 打开 `ViewController.swift`,在 `class UIViewController` 后添加 `UISCrollViewDelegate`
代理仅仅允许滚动视图可以进行滚动,但并没有明确何时才进行滚动。因此我们需要监听 ScrollView(捕捉用户动作)从而使当用户在上面做出滑动动作时ScrollView 开始进行滚动。函数如下:
```swift
func scrollViewDidScroll(_ scrollView: UIScrollView){}
```
上述内容完毕后,我们即可在 `viewDidLoad()` 中对 ScrollView 进行各项参数初始化设置:
```swift
self.scrollView.contentSize = self.imageView.frame.size //()
//
self.scrollView.contentSize = CGSize(width: lastImage.bounds.size.width, height:1000)
//
//
var point:CGPoint = scrollView.contentOffset
point.x += 150
point.y += 150
self.scrollView.contentOffset = point
self.scrollView.setContentOffset(contentOffset:CGPoint, animated:Bool)
//
self.scrollView.showsVerticalScrollIndicator = true self.scrollView.showsHorizontalScrollIndicator = false
///
self.scrollView.contentInset = UIEdgeInsets(top:100, left: CGFloat,bottom: CGFloat, right:CGFloat)
//
```
## 坐标参数
通常我们以屏幕左上角作为坐标系的原点垂直向下为y轴正半轴水平向右为x轴正半轴。坐标需要专用的类型来定义`CGPoint`
```swift
CGPoint
CGSize ScrollViewTableView
CGFloatCG
CGRect
```
## 实现竖直、水平滚动
1. 竖直滚动:竖直滚动既可以通过 storyboard 实现,也可以通过代码实现,在 `viewDidLoad()` 中添加代码部分如下:
```swift
self.scrollView.contentSize = CGSize(width: lastImage.bounds.size.wid th, height:1000)
```
其中,`width`、`height` 可以通过手动计算得出,也可以通过图片宽和高的对应乘积让编译器自己设置数值。值得注意的是,此处仅接受 `CGFloat` 格式。
2. 水平滚动:在纵向滚动处,我们可以通过 storyboard 来设置 `Image` 或者 `Button` 尺寸,但水平滚动则不同,我们无法通过一块屏幕来设置超出屏幕尺寸的多个横向图,因此需 要手动设置代码。在 `viewDidLoad()` 中:
```swift
var imageView1 = UIImageView()
imageView1.frame = CGRect(x: 0, y: 0, width: 414, height: 180)
imageView1.image = UIImage(named:"one.jepg")
scrollView.addSubview(imageView1)
self.scrollView.contentSize = CGSize(width: 2050, height: 0) self.scrollView.showsHorizontalScrollIndicator = false滚动播放逻辑
```
## 滚动播放逻辑
我们经常会在一些 app 上看到置顶的一些循环播放的广告图,这些广告被称之为轮播图。事实上,轮播图的本质也是一种滚动视图,接下来的两个部分你将学着自己构建出一个轮播图。
想要实现图片的横向滚动播放,需要我们在预定区域内横向同时放置 5 张图片,通过 `ScrollView` 控件实现 5 张图片的滚动查看。本章中,我们已经学习了通过一个 `Button` 来实现图片滚动的方法,此部分我们将把图片滚动和计时器(NSTimer)绑定到一起从而达到自动播放的效果。由于计时器应在程序初始时加入到内存中,因此我们将代码写入 `viewDidLoad()` 内。初始化计时器代码如下:
```swift
let timer:Timer? = Timer.scheduledTimer(timeInterval: 3.0, target: sel f, selector:#selector(myTimer), userInfo: nil, repeats: true)
timer?.fire()
```
请注意,在 Timer 函数中我们擅自使用了#selector(myTimer)方法,此类方法需要
Objective-C 类型函数才能执行。事实上,随着学习内容的深入你会发现:在 Swift 中不仅仅是计时器才会用到`#selector` 方法,其他情况下如音频播放等基础功能也同样需要自定义 `selector` 的方法。事实上,所有的监听事件都需要`@obcj` 的方法来实现不过随着版本的不断更新Apple 逐渐在试着将这些 `objc` 的方法淡出 Swift 舞台,但这并不代表着你现在可以完全放弃使用 OC 的方法,本笔记中也会延续这一习惯。回到计时器问题上,此刻我们需要定义一个 OC 类型且并列于 `viewDidLoad()` 的函数:
```swift
@objc func myTimer(){}
```
至此,初始化计时器已经完成。我们先不急着将坐标偏移量与计时器函数绑定到一起,先试着让 `ScrollView` 页面可实现手动在几个图片之间滚动,以及将 `pageControl` 的 `currentPage` 与当前 `ScrollView` 页面同步。
如何才能实现两者同步滚动?由于 `scrollView` 与 `pageControl` 是两个独立的控件,我们没办法将两者进行绑定,二者的同步似乎成了一个难题。然而,换个思路看这个问题, 从结果导向和用户体验角度来说,我们仅仅希望看到当 `scrollView` 滚动时,`pageControl` 也随之滚动,至于两者是否是真的同步我们并不关心,也不用去确认他们两个是否真的被 绑定到了一起,只要让它看起来是一体化就达到了我们的目的。对于这个问题,一种比较常用的解决思路是计算当前图片在 `scrollView` 中偏移的 x 值,并用 x 值和当前页面图片 (以左上角为原点,横向为 x 正半轴,纵向为 y 轴正半轴)初始的 x 坐标作商,结果取整来定位 `scrollView` 目前的页面。由于 `pageControl `是索引值,因此初始为 0在实际操作中我们需要根据不同情况来进行作商取整后的一些列加减数值实现同步。
在其他默认参数通过 storyboard 中设置完成后,我们可以通过监听滚动视图的值实现 两者同步,在 `scrollViewDidScroll()` 函数:
```swift
var page:Int
page = Int(self.scrollView.contentOffset.x / 414)
self.pageControl.currentPage = page
```
上述代码中,我们通过对滑动动作的监听,实现了当前页面与 pageControl 的同步 效果,接下来我们将这两者一并写入计时器方法中:
```swift
@objc func myTimer(){
if page==0{
self.scrollView.contentOffset.x = 0
page += 1
self.scrollView.setContentOffset(CGPoint(x:self.scrollView.contentOffset.x, y:0), animated: true) }
elseif page<5 && page>0 {
self.scrollView.contentOffset.x += point
page += 1
self.scrollView.setContentOffset(CGPoint(x:self.scrollView.contentOffset.x, y:0), animated: true) }
elseif page==5{
page=0
self.scrollView.setContentOffset(CGPoint(x: self.scrollView.contentOffset.x, y:0), animated: true)
}
}
```
至此,我们已经成功搭建了自己的第一个轮播图。事实上,计时器的使用对内存来说是一种负担,尤其是多个计时器同时启用时,它们会占据大量的内存空间,因此我们必须学会如何在程序结束的时候销毁计时器,后面我们会逐步了解。
## 轮播图参考代码
```swift
//定义部分
var page:Int = 0
let point:CGFloat = 414
//页面同步
func scrollViewDidScroll(_ scrollView: UIScrollView) {
page = Int(self.scrollView.contentOffset.x / 414)
self.pageControl.currentPage = page
self.scrollView.setContentOffset(CGPoint(x:self.scrollView.contentOffset.x, y:0), animated: true)
}
//手动添加五张图片
var imageView1 = UIImageView()
var imageView2 = UIImageView()
var imageView3 = UIImageView()
var imageView4 = UIImageView()
var imageView5 = UIImageView()
//在 viewDidLoad 里添加 image
imageView1.frame = CGRect(x: 20, y: 80, width: 374, height: 180)
imageView1.image = UIImage(named:"one.jepg")
scrollView.addSubview(imageView1)
imageView2.frame = CGRect(x: 434, y: 80, width: 374, height: 180)
imageView2.image = UIImage(named:"two.jepg")
scrollView.addSubview(imageView2)
imageView3.frame = CGRect(x: 848, y: 80, width: 374, height: 180)
imageView3.image = UIImage(named:"three.jepg")
scrollView.addSubview(imageView3)
imageView4.frame = CGRect(x: 1262, y: 80, width: 374, height: 180)
imageView4.image = UIImage(named:"four.jepg")
scrollView.addSubview(imageView4)
imageView5.frame = CGRect(x: 1676, y: 80, width: 374, height: 180)
imageView5.image = UIImage(named:"five.jepg")
scrollView.addSubview(imageView5)
//scrollView 总尺寸
self.scrollView.contentSize = CGSize(width: 2050, height: 0) self.scrollView.showsHorizontalScrollIndicator = false
//定义、开始计时器,在 override 内
let timer:Timer? = Timer.scheduledTimer(timeInterval: 3.0, target:self, selector: #selector(myTimer), userInfo: nil, repeats: true)
timer?.fire()
//定时器启用方法函数 @objc func myTimer(){
if page==0 {
self.scrollView.contentOffset.x = 0
page += 1
self.scrollView.setContentOffset(CGPoint(x:self.scrollView.contentOffset.x, y:0), animated: true) }
elseif page<5 && page>0 {
self.scrollView.contentOffset.x += point
page += 1
self.scrollView.setContentOffset(CGPoint(x:self.scrollView.contentOffset.x, y:0), animated: true) }
elseif page==5 {
page=0
self.scrollView.setContentOffset(CGPoint(x: self.scrollView.contentOffset.x, y:0), animated: true)
}
}
```

View File

@@ -0,0 +1,199 @@
# TableView的应用
## 什么是 TableView?
`TableView` 直译为表格视图,如今,我们手机上的各种 app 都存在着表格视图:当我们打开知乎时,首先看到的就是一个 `TableView`,首页上的每一个回答都是 `TableView` 中的一个 `cell`,只不它是一种自定义的表格视图;当我们在淘宝搜索栏中搜索某一关键词后,屏幕上出现的也是`TableView`,每一个商品都是`TableView`上的一个`cell`;当我们打开微信想找某个对话框时,对话框也是 `TableView` 上的 `cell`。通过本章以及下一章的学习,你将学习如何做出联系人列表,以及如何构建基本的表格视图界面。当然,仅有`TableView` 是不够的,在下一章结束后,你将掌握更多的技能。
## Storyboard中添加Table View
在storyboard控件库中搜索`Table View`,并拖拽至面板中,放大到与屏幕同尺寸。
![7](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/7.png)
页面的右侧罗列了Table View的一些基本属性第一个部分为单元格模式分为两种`Dynamic Prototypes``Static Cells`
`动态单元格`的原型在我们日常应用中十分常见例如iPhone上的`信息`应用就是一种动态表格,其特性为支持动态添加和删除。
`静态单元格`的数据内容相对固定很少会用到动态添加和删除但支持对表格的分组通常可以用作个人界面的信息显示。Storyboard中提供了静态单元格的简易搭建提示在实际的开发中很少这样使用本处仅作为演示使用。下图为静态单元格
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/8.png" alt="8" style="zoom:50%;" />
## 数据源代理
`UITableView` 继承自 `UIScrollView`,在进行 `ViewController` 编辑时,有如下两种方法对其进行代理:
- 第一种
1. 鼠标`右键`点击 `Table View`面板的空白处,拖拽至 `View Controller` 处与之连接,点击`dataSource``delegate`
![delegate](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/delegate.png)
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/datasource.png" alt="datasource" style="zoom:50%;" />
2.`ViewController.swift`中添加如下代码:
```swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
<#code#>
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
<#code#>
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
```
这就完成了TableView的初始化接下来我们仅需要在函数中添加相应代码即可运行。
- 第二种
1. 拖拽 `UITableView` 至代码中
2. 在 `ViewController` 中添加如下代码(或利用智能补全):
```swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
<#code#>
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
<#code#>
}
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = (self as UITableViewDataSource)
}
}
```
![10](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/10.png)
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/11.png" alt="11" style="zoom: 50%;" />
## TableView 的基本属性
完成代理后,代码部分需要设置 `UITableView` 的各项参数,与 `ScrollView `不同的是,`TableView` 存在两个必须继承的方法:
1. ```swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
```
2. ```swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
code
}
```
上述内容中,前者为每一个 section 有多少个 rows后者为对每个 rows 进行属性设置,
下一章中我会对 rows 中的属性进行详细说明,本章仅探讨 `TableView` 的一些性质。除了这两个必须继承的方法外,`TableView` 还有一个十分重要的内容:设置 section 数量。若想显示不同分组,需要我们手动添加一个方法,否则只显示第一组内的单元格(注:分组显示需要在 storyboard 中设置Grouped
```swift
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
```
若不设置此方法return 默认值为 1`TableView` 中除了上述的三个方法外,还有如下的几个属性:
```swift
rowHeight//统一设置所有行高度
separatorColor//分割线颜色
separatorStyle//分割线样式
tableHeaderView//可在分组单元格上方放置
title tableFooterView//可以用来显示加载更多页面
```
## 国家分组 demo
接下来以一个国家分组 demo 练习表格视图的分组:
```swift
func numberOfSections(in tableView: UITableView) -> Int {
//一共分几组,若没有此则默认为 1 section不会显示出了第一个以外的 section
return 3
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
//组标题,即页眉
if section == 0{
return "亚洲"
}else if section == 1{
return "非洲"
}else {
return "欧洲"
}
}
/* func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
//组注释,即页尾
if section == 0{
return "Asia"
}else if section == 1{
return "Africa"
}else {
return "Euro"
}
}
*/
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
//亚洲
return 3
}else if section == 1{
//非洲
return 2
}else {
//欧洲
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell.init(style: UITableViewCell.CellStyle.default, reuseIdentifier: nil)
if indexPath.section == 0 { //亚洲
if indexPath.row == 0 {
cell.textLabel?.text = "中国"
}else if indexPath.row == 1{
cell.textLabel?.text = "日本"
}else if indexPath.row == 2{
cell.textLabel?.text = "韩国"
}
}else if indexPath.section == 1 {
//非洲
if indexPath.row == 0{
cell.textLabel?.text = "南非"
}else {
cell.textLabel?.text = "坦桑尼亚"
}
}else {
cell.textLabel?.text = "英国"
}
return cell
}
```
值得注意的是如果我们在工程文件中大量套用if else函数会导致性能大大下降该部分仅为演示时使用在下一章中我们会集中探讨如何通过数组来定义 `cell`。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/12.png" alt="12" style="zoom:50%;" />

View File

@@ -0,0 +1,111 @@
# Cell
## Cell 的基本属性
在前一章的学习中我们初步学习了 `cell`,但事实上,在国家分组 demo 中我们仅仅是构建了一个动态单元格(Dynamic Prototypes)`TableView`中的`Cell`共有两种类型,分别是动态单元格(Dynamic Cell)和静态单元格(Static Cell),前者往往用于联系人列表、商品信息表、新闻软件的信息栏等图片和文字需要经常变化的地方,而后者往往被用于系统设置、个人页面的设置等不轻易改变单元格本身属性内容的位置。
通常来说,定义一个 `cell` 通常有以下两种方式:
```swift
let cell = UITableViewCell.init(style: UITableViewCell.CellStyle.default, re useIdentifier: nil)
let cell = tableView.dequeueReusableCell(withIdentifier: "RegistrationCell",
for: indexPath)
```
在简单的页面设置中我们通常可以用第一类定义cell值得注意的是例子中给出的 `CelStyle.default``cell`的一种style该格式不会显示除主标题以外的任何内容对于本章的Emoji案例来说这显然是不合适的因此我们在具体设置时将其改为`CellStyle.subtitle`。以下罗列了一些cell的属性
```swift
imageView//
textlabel//
detailTextLabel//
accessoryType//
accessoryView//
backgroundColor//
backgroundView// UIImageView
selectedBackgroundView//
```
## Emoji 的 TableView 显示
此前我们通过 if-else 函数定义了一些单元格。在实际工程文件中,我们往往需要通过数组来确定单元格数量,在后面的章节你会了解到,开发工程师们会在互联网中引用 JSON 文件来直接调用服务器中的数组,这就赋予了 app 生命力,让其不断更新数据。本部分我们通过自定义一个 Emoji 数组来模拟这一过程,需要注意的是,我们将在此使用**动态单元格**(Dynamic Prototypes)。
接下来我们将通过一个构建demo案例Emoji的`tableView`显示来学习数组与cell定义之间的联系在以后的学习过程中我们通常要用到这种方法。
1. 并列于 `UIViewController` 定义一个类:
```swift
class Emoji {
var symbol: String
var name: String
var description: String
var usage: String
init(symbol: String, name: String, description: String, usage: String) {
self.symbol = symbol
self.name = name
self.description = description
self.usage = usage
}
}
```
2. 代理、继承 `UITableViewDataSource`
```swift
class ViewController: UIViewController,UITableViewDataSource {}
```
3. 定义 `UITableViewCell` 属性:
```swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
if section == 0 {
return emojis.count
}else{
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Emoji:String = "Emoji"
let cell:UITableViewCell = UITableViewCell.init(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: Emoji)
let emoji = emojis[indexPath.row]
cell.textLabel?.text = "\(emoji.symbol) - \(emoji.name)"
cell.detailTextLabel?.text = emoji.description
return cell
}
```
4. 定义子类:
```swift
var emojis: [Emoji] =
[Emoji(symbol: "😀", name: "Grinning Face", description: "A typical smiley face.", usage: "happiness"),
Emoji(symbol: "😕", name: "Confused Face",description: "A confused, puzzled face.", usage: "unsure what to think; displeasure"),
Emoji(symbol: "😍", name: "Heart Eyes", description: "A smiley face with hearts for eyes.", usage: "love of something; attractive"),
Emoji(symbol: "👮", name: "Police Officer", description: "A police officer wearing a blue cap with a gold badge.", usage: "person of authority"),
Emoji(symbol: "🐢", name: "Turtle", description:"A cute turtle.", usage: "Something slow"),
Emoji(symbol: "🐘", name: "Elephant", description: "A gray elephant.", usage: "good memory"),
Emoji(symbol: "🍝", name: "Spaghetti",description: "A plate of spaghetti.", usage: "spaghetti"),
Emoji(symbol: "🎲", name: "Die", description: "A single die.", usage:"taking a risk, chance; game"),
Emoji(symbol:"⛺", name: "Tent", description: "A small tent.", usage: "camping"),
Emoji(symbol: "📚", name: "Stack of Books", description: "Three colored books stacked on each other.", usage: "homework, studying")]
```
至此,你已经认识了一些基本控件。在接下来的两章中,我将通过酒店管理系统与贪吃蛇来帮助你熟悉更多的基本控件并强化你的基本功,学习完毕后你将具备最基本的一些开发能力,并且能够搭建自己的一些简单 app继续加油

View File

@@ -0,0 +1,61 @@
# 常见的Controller概览
## 主视图控制器 View Controller
在前面的任务中我们打开Storyboard即可看到主视图控制器 View Controller这是一种最基本、最常见的视图控制器。例如当我们需要实现Table View的功能时我们可以在控件库中添加 Table View插件于 View Controller中也可以添加Scroll View于 View Controller中以实现页面滚动。View Controller更像是一张空白的A4纸我们可以在上面书写任何想要的内容。
在本章的学习过程中,请确保您的视图控制器中的一个处于`Is Initial View Controller`状态,这样您的程序在运行时才不会崩溃。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/ViewController.png" alt="ViewController" style="zoom: 33%;" />
## Table View Controller
前文我们已经通过Table View控件实现了表格单元。事实上控件库中提供了一种简易的实现方式Table View Controller直接添加相应控制器即可该Controller与Table View完全一致你可以直接在右侧信息栏中设置相关属性。
如果把View Controller比作空白的A4纸那么在View Controller上添加Table View控件相当于在A4纸上画满一条一条的格线——这当然是一种办法但我们常常还有另外的一种简易方法直接使用带格线的笔记纸。Table View Controller正是这种带格线的笔记纸。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Table View Controller.png" alt="Table View Controller" style="zoom: 50%;" />
## Page View Controller
某乎的首页界面就是一个Page View ControllerPage View并不是在底部的控制栏中进行切换你可以看到即使在相同的Tab Bar Item中我们也可以对页面进行左右切换这正是Page View Controller的用处。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/page1.PNG" alt="page1" style="zoom: 20%;" /> <img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/page2.PNG" alt="page2" style="zoom:20%;" />
在Xcode中我们可以使用Page控件进行实现当然也可以使用Page View Controller来“一劳永逸”地解决Page切换问题。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Page View Controller.png" alt="Page View Controller" style="zoom:50%;" />
## Navigation Controller
你可能并不清楚Navigation Controller究竟指的是什么但是你一定用过且见过Navigation Controller。例如在手机的设置中任何一个界面都是一个Navigation它常常与带Cell的Table View一起出现
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/navigation bar.PNG" alt="navigation bar" style="zoom: 25%;" />
上图中,`主屏幕``设置` 回退button都是Navigation Controller上的一部分。
![Navigation Controller](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Navigation Controller.png)
## Tab Bar Controller
上面的Page View Controller提供了一种在页面内进行切换的方式。然而以微信为例如果我们要实现不同页面的切换我们需要点击屏幕下端的item进行切换。Tab Bar Controller正是实现该功能的控制器。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/tab bar item.jpg" alt="tab bar item" style="zoom: 33%;" />
在Xcode中添加Tab Bar Controller会直接出现三个视图控制器当然我们可以手动添加更多分别是Tab Bar Controller主控制器与两个Item实现我们可以在右侧的属性栏中手动选择每个Item对应的图标、文字当然也可以设置更多的属性你可以自行探索。
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Tab Bar Controller.png" alt="Tab Bar Controller" style="zoom:50%;" />
## Collection Controller
除了上述视图控制器外还有一种常见的视图控制器Collection Controller这是一种展览、罗列内容相关的Controller。例如一些电子杂志app会将近几期发行本以矩阵形式罗列一些音乐app也会以这种方式罗列自己的唱片集合。iPhone中的`图书` 功能就是Collection Controller的一种
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Collection.PNG" alt="Collection" style="zoom: 15%;" /> <img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/Collection View Controller.png" alt="Collection View Controller" style="zoom: 40%;" />
熟悉这些基本的视图控制器可以帮助我们在实际开发过程中设计出更符合逻辑的app后面我们会在这些控制器上进行操作以实现各种不同的内容。

View File

@@ -0,0 +1,166 @@
# 动画、音频与视频
## 动画
流畅的动画是 iOS 的灵魂所在。对于开发者而言,合理地使用动画,让用户体验得到提升是攻城狮们的必修课程。在前面的课程中我们 已经熟悉了对 Swift 的基础控件,接下来我们将把学习内容放到设计结构上。
对于动画的应用一般在 View 控件上,动画的种类大体上分为仿射变换、旋转变换以及平移三 种,对于动画过程中的速度时间我们都可以进行设置,这三种变换是所有动画的基础,例如:我们可以通过平移来实现 app 的加载和退场,可以使用仿射变换实现音乐播放时封面的动画,从而让用户有真实感。此外,我们还可以通过旋转来使整个程序增添一份趣味。下面的代码罗列了一些基本的动画使用方法,你需要熟练掌握并且试着学会如何应用。在 playgrounds 中:
```swift
import UIKit
import PlaygroundSupport
// View
let liveViewFrame = CGRect(x: 0, y: 0, width: 500, height: 500) let liveView = UIView(frame : liveViewFrame) liveView .
backgroundColor = . white
PlaygroundPage . current . liveView = liveView
let smallFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
let square = UIView(frame: smallFrame)
square.backgroundColor = .purple
liveView.addSubview(square)
//
UIView.animate(withDuration: 2.0) {
square . backgroundColor = . orange
let scaleTransform = CGAffineTransform(scaleX : 2.0 , y: 2.0) //仿
let rotateTransform = CGAffineTransform(rotationAngle: .pi)//
let translateTransform = CGAffineTransform(translationX:200, y: 200) //
let comboTransform = scaleTransform.concatenating(rotateTransform ).concatenating (translateTransform ) square .transform = comboTransform //
}
```
## 短效果音播放
一个有趣的 app 离不开各种令人印象深刻的音效。在 Swift 中,我们通常使用 AudioToolbox 与 AVFoundation 来播放音频和视频。假设导入一个 30s 内的 wav 格式音频,并将其命名为 myVoice 接下来,我们需要将该音频的所在路径设置为虚拟的 url 地址,并将音频播放的地址设置为该地址:
```swift
import UIKit
import AudioToolbox
class ViewController : UIViewController{
override func viewDidLoad () {
super.viewDidLoad ()
var _soundId : SystemSoundID = 0
let path = Bundle.main.path(forResource: myVioce,ofType: wav)
let soundUrl = URL( fileURLWithPath : path ! )
AudioServicesCreateSystemSoundID ( soundUrl as CFURL,&_soundId )
AudioServicesAddSystemSoundCompletion(_soundId , nil , nil ,{(soundID , clientData ) > Void in
print()
AudioServicesPlaySystemSound ( soundID )
}, nil)
AudioServicesPlaySystemSound ( _soundId )
}
}
```
## 长音乐音乐播放
在一款 app 中,仅仅有 30s 的效果音可能还不够有时候我们需要导入长音乐。Swift 中内置了一款音乐播放器,对于基础开发者来说足够应用。该播放器的设置过程和短效果音的思路相同,我们也需要设置 url 路径来导入我们的本地音乐。请注意Swift 内置的音频播放器中并没有暂停和继续播放的功能,我们需要手动设置一个 Button 来实现该效果:
```swift
import UIKit
import AVFoundation
class ViewController: UIViewController,AVAudioPlayerDelegate {
var audioPlayer:AVAudioPlayer = AVAudioPlayer()
// AVAudioPlayer
override func viewDidLoad() {
super.viewDidLoad()
//
let path = Bundle.main.path(forResource: "兰亭序", ofType: "mp3") // URL
let soundUrl = URL(fileURLWithPath: path!)
do{
try audioPlayer = AVAudioPlayer(contentsOf: soundUrl) audioPlayer.volume = 1.0
// 1.0
audioPlayer.numberOfLoops = -1 //-1
audioPlayer.delegate = self audioPlayer.play()
} catch {
print(error)
}
///
let stopMusic = UIButton(frame: CGRect(x: 20, y: 80, width: 280, height: 44))
stopMusic.backgroundColor = UIColor.blue
stopMusic.setTitle("暂停/恢复音乐", for:UIControl.State.init(rawValue:0))
//
stopMusic.addTarget(self, action: #selector(ViewController.pauseOrResumeMusic), for: .touchUpInside)
self.view.addSubview(stopMusic)
}
// objc
@objc func pauseOrResumeMusic(){
if self.audioPlayer.isPlaying{
//isPlaying
self.audioPlayer.pause()
}else{
self.audioPlayer.play()
}
}
func audioPlayerBeginInterruption(_ player: AVAudioPlayer) {
print("被打断")
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("播放完成")
}
}
```
附件中携带了一份我自己制作的兰亭序伴奏demo.mp3你可以用这个音频文件进行功能实现尝试。
## 视频播放
实现了音频播放该如何实现视频播放呢Swift 中内置了视频播放的功能,总体上来说,本地视频播放的思路和音频一样,都需要我们设置视频的 url 地址,将本地视频导入其中。在此之前我们需要导入 AVFoundation 头文件,在 `viewDidLoad()`中:
```swift
let moviePath = Bundle.main.path(forResource: "movie", ofType: "mp4")
let movieURL = URL(fileURLWithPath: moviePath!)
let avPlayer = AVPlayer(url: movieURL as URL)
let avPlayerLayer = AVPlayerLayer(player:avPlayer)
avPlayerLayer.frame = self.view.bounds
avPlayerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill self.view.layer.addSublayer(avPlayerLayer)
avPlayer.play()
```
### 借助播放器
在上面的代码中,我们实现了视频的播放,不过你可能发现在该 项目中我们无法进行暂停与快进,更不用提画中画和声音等功能,要想实现这些内容,我们需要借助 Swift 内置的播放器:
```swift
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// URL
let moviePath = Bundle.main.path(forResource: "movie", ofType: "mp4")
let movieURL = URL(fileURLWithPath: moviePath!)
//
let avPlayer = AVPlayer(url:movieURL as URL)
let playerVC = AVPlayerViewController()
playerVC.player = avPlayer
playerVC.videoGravity = AVLayerVideoGravity.resizeAspect
/*.resizeAspectFill
.resizeAspect */
playerVC.allowsPictureInPicturePlayback = true
playerVC.showsPlaybackControls = true playerVC.view.frame = self.view.bounds
playerVC.player!.play()
self.view.addSubview(playerVC.view)
}
}
```

View File

@@ -0,0 +1,92 @@
# 基本权限与url访问
## 分享图片
我们的 app 肯定会用到各种权限,权限的申请也是开发者需要学习的一门课程,本章中提供了一些基本的权限请求方式,在后面的基础功能部分你将学习更多的内容。
此部分提供了分享照片的基本权限,我们可以通过一个 Button 来分享照片:
```swift
@IBOutlet var imageView: UIView!
@IBAction func shareButton(_ sender: Any) {
guard let image = imageView else { return }
let activityController = UIActivityViewController(activityItems:[image],applicationActivities: nil)
activityController.popoverPresentationController?.sourceView = sender as? UIView present(activityController, animated: true, completion: nil)
}
```
## 网页链接
如果想要 `Button` 连接到浏览器,则需要对网页做出请求,在此前需要导入 `Safari Services` 头文件:
```swift
import SafariServices
@IBAction func Safari(_ sender: Any) {
if let url = URL(string: "http://www.bilibili.com") {
let safariViewController = SFSafariViewController(url:url)
present(safariViewController, animated: true,completion: nil)
}
}
```
## 提示与弹窗
如果想要获得照片权限,你需要一个弹窗,不仅如此,在选择头像的功能中,你也需要弹窗提示:从照片中选择、拍摄照片和取消三个部分:
```swift
let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: {action in print("User selected Camera action") })
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .default, handler: { action in print("User selected Photo Library action") })
alertController.addAction(cancelAction)
alertController.addAction(cameraAction) alertController.addAction(photoLibraryAction)
alertController.popoverPresentationController?.sourceView = sender as? UIView present(alertController, animated: true, completion: nil)
let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { action in print("User selected Camera action") })
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .default, handler: { action in print("User selected Photo Library action") })
alertController.addAction(cancelAction)
alertController.addAction(cameraAction) alertController.addAction(photoLibraryAction) alertController.popoverPresentationController?.sourceView = sender as? UIView present(alertController, animated: true, completion: nil)
```
## 请求相机权限
iOS对相机以及其他各种权限的设置较为复杂目前通用有两种手段获取相机权限第一种通过 `ImagePickerController` 来实现,智能识别部分用到的就是这个,但是设置起来十分繁琐。不过好在还有第二种,通过 `Info` 中设置相关参数,直接访问即可,在 `Info.plist` 文件中添加:
```swift
Privacy - Photo Library Additions Usage Description
```
赋值 `value`
```swift
To share photos from camera or photo library
```
相机请求:
```swift
@IBAction func photosButtonTapped(_ sender: UIButton) {...}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageView.image = selectedImage
dismiss(animated: true, completion: nil)
}
}
```

View File

@@ -0,0 +1,61 @@
# 代码启动与登录界面
## 代码启动
在大型工程文件中我们常常要避免使用storyboard因为大量的storyboard会造成卡顿内存占用过多。下面我们将介绍如何使用代码启动我们的app。
**Step 1打开工程文件在左侧导航栏中删除storyboard**
![21](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/21.png)
**Step 2**在`Info.plist`中删除`Main storyboard file base name`一行
![22](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/22.png)
**Step 3** 在左侧导航栏----`Info.plist`----`Application Scene Manifest`----`Scene Configuration`----`Application Session role`----`Item -(Default Configuration)`----`Storyboard Name`右侧Main中删除该行
![23](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/23.png)
**Step 4在左侧SceneDelegate.swift中添加如下代码**
```swift
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
```
![setup](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/setup.png)
即可完成!
## 设置app的Icon
你可以将喜欢的图片用作自己app的Icon这是一个在线免费转换尺寸的网址
https://icon.wuruihong.com
![figure](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/figure.png)
Xcode的Assets.xcassets中罗列了该应用可能与用到的所有尺寸的Icon你可以将上述网站下载得到的文件夹拖拽至Appicon处系统会自动进行填充。
## 设置启动页面
打开各种app后映入眼帘的往往不是空白屏幕而是伴有启动页面的等待加载部分如何实现用自己的图片进行加载下面我们就来一起设置
iOS 中设置启动页有两种方式 Launch Image 和 LaunchScreen本部分我们以Launch Image为例
**Step 1**在工程 targets--Build Settings 搜索 Asset Catalog Launch Image Set Name 然后设置创建的启动页名字LaunchImage。
![13](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/13.png)
**Step 2**再在Info.plist中删除 `Launch screen interface file base name`并添加 `Launch image`并设置 `LaunchImage`
![14](/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/14.png)
**Step 3**资源文件中添加LaunchImage放入不同尺寸的图片。
**Step 4**点击运行
<img src="/Users/mac/Desktop/iOSdev/Task01基础插件与功能/img/15.png" alt="15" style="zoom:33%;" />

View File

@@ -0,0 +1,210 @@
{
"images" : [
{
"extent" : "full-screen",
"filename" : "Default-2688h.png",
"idiom" : "iphone",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"scale" : "3x",
"subtype" : "2688h"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape-2688h.png",
"idiom" : "iphone",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "3x",
"subtype" : "2688h"
},
{
"extent" : "full-screen",
"filename" : "Default-1792h.png",
"idiom" : "iphone",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"scale" : "2x",
"subtype" : "1792h"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape-1792h.png",
"idiom" : "iphone",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "2x",
"subtype" : "1792h"
},
{
"extent" : "full-screen",
"filename" : "Default-2436h.png",
"idiom" : "iphone",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x",
"subtype" : "2436h"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape-2436h.png",
"idiom" : "iphone",
"minimum-system-version" : "11.0",
"orientation" : "landscape",
"scale" : "3x",
"subtype" : "2436h"
},
{
"extent" : "full-screen",
"filename" : "Default-736h.png",
"idiom" : "iphone",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "3x",
"subtype" : "736h"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape-736h.png",
"idiom" : "iphone",
"minimum-system-version" : "8.0",
"orientation" : "landscape",
"scale" : "3x",
"subtype" : "736h"
},
{
"extent" : "full-screen",
"filename" : "Default-667h.png",
"idiom" : "iphone",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "2x",
"subtype" : "667h"
},
{
"extent" : "full-screen",
"filename" : "Default@2x~iphone.png",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x",
"subtype" : "retina4"
},
{
"extent" : "full-screen",
"filename" : "Default-Portrait~ipad.png",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "1x"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape~ipad.png",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"orientation" : "landscape",
"scale" : "1x"
},
{
"extent" : "full-screen",
"filename" : "Default-Portrait@2x~ipad.png",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "full-screen",
"filename" : "Default-Landscape@2x~ipad.png",
"idiom" : "ipad",
"minimum-system-version" : "7.0",
"orientation" : "landscape",
"scale" : "2x"
},
{
"extent" : "full-screen",
"filename" : "Default~iphone.png",
"idiom" : "iphone",
"orientation" : "portrait",
"scale" : "1x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "full-screen",
"filename" : "Default-568h@2x~iphone.png",
"idiom" : "iphone",
"orientation" : "portrait",
"scale" : "2x",
"subtype" : "retina4"
},
{
"extent" : "to-status-bar",
"filename" : "Default-No-StatusBar~ipad.png",
"idiom" : "ipad",
"orientation" : "portrait",
"scale" : "1x"
},
{
"extent" : "full-screen",
"idiom" : "ipad",
"orientation" : "portrait",
"scale" : "1x"
},
{
"extent" : "to-status-bar",
"filename" : "Default-Landscape-No-StatusBar~ipad.png",
"idiom" : "ipad",
"orientation" : "landscape",
"scale" : "1x"
},
{
"extent" : "full-screen",
"idiom" : "ipad",
"orientation" : "landscape",
"scale" : "1x"
},
{
"extent" : "to-status-bar",
"filename" : "Default-No-StatusBar@2x~ipad.png",
"idiom" : "ipad",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "ipad",
"orientation" : "portrait",
"scale" : "2x"
},
{
"extent" : "to-status-bar",
"filename" : "Default-Landscape-No-StatusBar@2x~ipad.png",
"idiom" : "ipad",
"orientation" : "landscape",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "ipad",
"orientation" : "landscape",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.