当前位置:首页 » 编程语言

第五章 :创建一个简单的基于Table View的应用程序

2015-09-13 14:02 本站整理 浏览(177)

第五章 :创建一个简单的基于Table View的应用程序

译者注:由于本人英语水平有限,尽可能描述出作者的本意。如有错误,及时指出。文中会省略部分技术无关的赘述

Everything is easier said than done. Wanting something is easy. 
    Saying something is easy. The challenge and the reward are in the doing.                                                                                                    
                                                                                                    – Steve Maraboli


介绍UITableView

现在你对prototype和我们的demo app有个基础的了解 。在本章,我们将使用UItableView建立一个更有趣的app 。一旦你掌握了这个技术和table view的自定义(下章讨论),我们将会开始我们的Food Pin app开发。
首先,table view 究竟是什么? 他是IOS apps中最常见的UI元素 。大多数app(除过游戏),在某些方面 ,利用表视图来显示内容。最好的例子就是苹果的内建应用。你的联系人列表就是用tableview展示的 。 邮件也是,使用tableview展示你的邮箱和电子邮件 。 tableview不仅可以展示文本数据,还可以展示图像数据 。TED ,Google+ 和 Airbnb 也是很好的例子 。上图展示了一些简单的基于tableview的app ,尽管他们看起来不一样,但是他们都是利用tableview 开发的 。

创建一个简单的Table工程

我们开始创建一个简单的app ,这个app真的很简单 。 只是来展示一些餐馆名字的列表 。 这个tableview 看起来并不那么好看 。我们将在下一章改进它 ,打开Xcode ,创建一个”Single View application”

按照第一章讲得填好项目名Simple Table组织名随便填一个,不要勾选User Core Data , 选个好存放项目的目录 ,进入项目 。

storyboard 设计


首先我们会创建一个用户界面添加一个tableview 。 选择”Main.storyboard”切换到storyboard的编辑界面 。
我们不适用Size Classes ,按照第一章的方法把Size Classed的勾选去掉 。
下一步 ,从对象库拖一个table view 试图到当前试图 。如下图

然后,选择这个tableveiw 。 在属性编辑器中(如果没有在Xcode中显示 ,选择 View > Utilities > Show Attributes Inspector) , 把Prototype Cells 从 0 改成 1 。

(本图为译者添加)
tableView中就会出现一个prototype cell 。prototype cells 允许你很容易的去射你的table view cell 。它还配备了一些标准的单元格风格 包括basic (基础类型),right detail (右边明细),left detail (左边明细)和 subtitle (副标题) 。我们这个例子中会使用basic。
选择cell 打开属性编辑器 ,把cell的style 改成Basic ,这个类型足够显示文字和图片 。 此外,把Identifier 设置位 Cell ,这个是prototype cell的唯一标示符 。我们一会儿会在代码中使用到它 。

不写任何代码,Run你的app

在继续之前 , 在模拟器上Run你的app 。
模拟器上得界面显示如图

非常简单,对吗?你已经为你的app创建了一个table view 。然而它没有任何数据 ,下一步我们将会写一些代码给这个tableview 添加一些数据

UITableView 和协议

我前面提到我们会使用一些IOS SDK提供的类,这些类被组织成framework(框架)。UIKit框架是我们最经常使用的框架 。
它提供一些类去构建和管理你的app界面 。所有用户界面叛变对象库提供的对象都是这个框架提供的 。第一章用到的按钮控件和这章用的table veiw控件都是它提供的 。table view的类实际上是UITableView 。 你可以在对象库点击任何一个对象 ,它的类名都会弹出来 。

现在你已经知道Table View和UITableView之间的关系了 。我们将会写一些代码给table增加一些数据 。选择ViewController.Swift 。在代码编辑器中”UIViewController”后面添加”,UITableViewDataSource,UITableViewDelegate”来实现对应的协议 。
你把上面的协议添加上后,Xcode就会报错 ,当有错误的时候Xcode会显示一个红色的感叹号 。 点击左侧的小感叹号Xcode 将会把这行代码高亮 而且会显示出错误信息 。这个信息会提示你错误的信息但是不会提供解决方案 。

“ViewController does not conform to protocol
UITableViewDataSource” 是设么意思呢?
UITableViewDelegateUITableViewDataSource 是swift中的协议 。为了在table View中显示数据 ,我们必须符合协议中的规定并提供一个对象(这里就是ViewController)实现那些强制性的方法 。
你也许会疑惑 ?这些协议是什么? 为什么要使用这些协议 ?
我们来打个比方 , 你雇佣了一个平面设计师 帮你设计公司的logo 。他是一个数量的设计师可以设计各种logo 。但是它不能立即开始设计 。 在让它设计之前你至少要给他提一些需求比如公司的名字 、颜色偏好、商业背景。然而,你非常忙。你委托你的个人助理去提供这些需求 。
在IOS编程中 ,UITableView就像那个图像设计师 。他足够灵活在table中显示各种数据 。 你也许想显示一些国家或者联系人名称 或者一些其他的东西 。我们将展示一个餐馆列表附带缩略图 。
但是它需要一个 代理去提供协议基础信息 如:
你想在这个table中展示多少行数据 ?
table中的数据是什么 ?例如你想给第二行显示什么?你想给第五行显示什么?
上面的东西像一个个人助理,ViewController充当一个代理去提供必要的信息 。
然而你怎样告诉UITableView展示什么数据 ? UITableViewDataSource是关键 。他是你的数据和tableview的桥梁 。这个协议定义了一写方法让你去实现 。下面是两个UITableViewDataSource必须实现的方法:
tableView(_:numberOfRowsInSection:)
tableView(_:cellForRowAtIndexPath:)
你需要的是有一个对象去实现上面的方法 ,以便让UITableView知道显示多少行和每行显示什么数据 。 这个协议还定义了一些可选方法 ,但我们这里并不准备讨论他们 。
UITableViewDelegate处理table view的外观 ,协议中所有方法都是可选的 。 它帮你管理你行高 配置section 的header 和 footer ,重新给tableview cells排序 等等 。我们例子中不会用到这些方法 。我们后面章节会使用他们 。
带着这几基础知识,我们继续编写代码 。 选择ViewController.swift 声明一个变量存储数据 。
var restaurantNames = ["Cafe Deadend", "Homei", "Teakha", "Cafe Loisl", "Petite Oyster", "For Kee Restaurant", "Po's Atelier","Bourke Street Bakery", "Haigh’s Chocolate", "Palomino Espresso","Upstate", "Traif", "Graham Avenue Meats And Deli", "Waffle &Wolf", "Five Leaves", "Cafe Lore", "Confessional", "Barrafina","Donostia", "Royal Oak", "CASK Pub and Kitchen"]

在这里例子中,我们使用一个数组去存储数据 。 swift中数组使用不再赘述 。
下一步 ,我们来实现
UITableViewDataSource
协议的两个必要的方法
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // Return the number of rows in the section.
    return restaurantNames.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
    let cellIdentifier = "Cell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath:
    indexPath) as UITableViewCell
    // Configure the cell...
    cell.textLabel.text = restaurantNames[indexPath.row]
    return cell
}

第一个方法告诉table View某个section中共有多少行(一个tableview可以有多个section 默认是一个) 。 这个简单取数组的长度。
第二个方法展示每行数据的时候都会调用 。使用indexPath对象 ,我们可以得到当前行(indexPath.row) 。以便我们从restaurantNames数组中取出索引元素赋值给cell的text Label 去显示 。
那么dequeueReusableCellWithIdentifier这个方法是什么意思呢 ?
那个方法是通过唯一标示符(在storyboard中页面的identifier属性定义的”Cell”)从table cell队列中取出可重复利用的tableview cell 。
你希望你这个tableview app能够快速响应,即使是处理上千条数据 。如果你每次都分配一个新的cell而不是重用它。你的app会使用更多的内存 ,当用户滚动tableview的时候还会反应呆滞 。分配每一行都会有性能开销,特别是在很多一段时间内分配。
屏幕可以显示大小是固定的 ,即使你需要显示1000条记录 ,屏幕最多显示10条 。为什么要创建并分配1000个tableview cell而不是创建10个tableview cell并且重用他们呢 。这将节省大量的内存也会使你的app效率更高 。因此处于性能考虑,你应该重用cell

现在点击Run按钮去测试你的app , 哎呀!app还是显示空的。
为什么tableview没有像我们预期那样显示内容呢?我们已经写了显示他们的方法呀?
还有一件事情没做。

连接DataSource 和 Delegate

尽管我们的ViewController 已经实现了协议的方法 , 但是UITableView并不晓得 。我们需要告诉UITableView ViewController就是他data source的代理 。
回到storyboard 。按住control建不放 ,点击table view拖到左边的饿View Controller 。如图

放开,在弹出菜单中选择 dataSource ,重复上面的操作 ,再选择delegate 。

为了确保连接正确 , 在左边的窗体选择tableview右击显示那些连接 。

测试你的app

最后我们点击Run按钮让我们的app在模拟器上跑起来 。你的app现在战士了餐馆名字的列表 。

给tableview添加缩略图

这个tableview看起来太单调了 ,我们需要给每行添加图片 。UITableView使他变得很简单 ,我们只需要添加一行代码就能搞定 。
首先需要从这里下载示例中的图片https://www.dropbox.com/s/d1rwisj6pt89db3/restaurantimages.zip. (国外地址需要*)这里包含三个图像文件。所有的文件都是一样的,只是不同的分辨率 。当你开发一个IOS应用的时候 。推荐你准备三套图片 。@3x后缀名的是给iPhone plus用的,@2x给iPhone 4/4s/5/5s/6 , 没有 @ 后缀名的是给一些没有retain的老设备使用的 。
Xcode项目包含一个 image asset 目录(images.xcassets) 供你去管理大多数类型的图像文件 。你把那些图片解压,选择images.xcassets ,把那几个文件从Finder中拖进来就可以了。

系统自动事变retain 和 非 retain图像 。一旦图像在图像组中可用 ,你就可以在代码中是用不带后缀名的文件名称来访问他们。

现在打开ViewController.swift在tableView(_:cellForRowAtIndexPath:)方法的return cell前添加
cell.imageView.image = UIImage(named: "restaurant")

UIImage是由UIKit框架提供的 。它支持各种图像格式比如png ,gif ,jpeg .简单的传递图像的名称它将帮你家在这个图像 。
我们使用单元格的基础样式 ,它有一块默认的区域用来显示图像 。这行代码就是让UITableView在默认图像显示区域显示制定的图像 。现在点击Run按钮 SimpleTable app会在每行显示图像 。

隐藏状态栏

从IOS 7开始ViewController会在整个屏幕显示 。tableview的内容和状态栏重叠了 ,看起来并不美观 。
一个简单的措施就是隐藏状态栏 。你可以在任意一个Viewcontroller中控制它的状态栏的外貌。 如果你再一个特定的页面不想显示状态栏 。仅仅需要添加下面的代码 。
override func prefersStatusBarHidden() -> Bool {
    return true
}

把上面的代码添加到ViewController.swift中 ,重新运行app ,现在状态栏被隐藏了。

给UITableView添加Auto Layout 约束

你已经做了很多了 。你第二个app在iPhone 5/5s上看起来不错 ,你有没有试过在iPhone 4s上运行 或者横屏显示 ?你可以试试这么做。
下图横屏的情况

table View并没有完全显示 。你也许清楚你需要使用Auto Layout 使它充满屏幕 。
打开storyboard选择tableview 。在Auto Layout菜单点击 Pin 按钮打开Pin 工具菜单 。选择每个红色虚线,一旦选中这些虚线就变成了实线 。点击”Add 4 Constraints” 按钮添加这些约束 。这里我们对UITableview的4个边定义了四个约束 。另外, 我们想要保证UITableView的底部不要超过Bottom Layout Guide。 如果在左边窗体中展开约束项目 你会看到两个横向的空间约束和两个竖向的束。两个水平空间约束可以确保左侧和右侧表视图将延伸到视图的边缘。垂直约束用于解决了3.5英寸的屏幕问题 。UITableView的底部和Bottom Layout Guide对齐 。换句话说,你的app将自动调整大小适配小屏幕 。
非常好 ,现在测试你的app 。你的app不管任何屏幕下都可以完美显示包括横屏 。

你的练习作业

到目前为止你的demo app在每个cell中展示了固定的图像 。尝试调整你的app代码 ,让他在每个cell中显示不同的图像 。

总结

表视图是在IOS编程最常用的要素之一。如果你完全理解上面讲得 ,你应该对构建自己的table view app有个很好的想法 。我尝试去把demo中的每个点都讲得非常简单 。在真实的项目中table数据不会是简单的”hard-code”。
通常他们从文件、数据库后者其他地方中加载。我们后面会讨论这些。然而你首先要确认你了解tableview怎么工作 ,否则把这章再读一遍 。
你可以下载示例工程供你参考:https://www.dropbox.com/s/kufb6373g1rrsn8/SimpleTable.zip.