我们实现了UITableView基本的两个data source方法。接下来,我们继续定义EpisodeItem Cell和UITableView的用户交互实现。
使用Cell tag
在UITableViewCell里,我们可以为每一个UI对象设置一个Tag,方便我们找到这个UI对象。回到Storyboard,选中EpisodeItem里的UILabel,在"Attribute inspector"里,把它的Tag设置为1024。
"确保你选中的是UILabel而不是EpisodeItem。如果你不确定是否选对了,在Document outline里选择是更方便的方式。至于Tag为什么是1024,没什么特别的理由,只要不是0,任何你喜欢的值都可以。"
特别提示
设置好Tag之后,我们回到EpisodeListViewController.swift,修改之前创建Cell的代码:
override func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return 10;
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1\. Create the cell object
let cell =
tableView.dequeueReusableCellWithIdentifier(
"EpisodeItem", forIndexPath: indexPath)
// 2\. Get the label object
let label = cell.viewWithTag(1024) as! UILabel
// 3\. Set label text
label.text = "Episode " + String(indexPath.row)
return cell;
}
当我们获得了Cell对象之后,我们用Tag读取到了其中的UILabel对象,然后设置了它的text属性,这样,每一个Cell显示的内容就不同了。按Command + R重新编译执行,查看结果:
使用Model表示数据
在之前的例子里,我们直接在Controller里"制造"了要显示在Cell里的内容。这只能作为一种演示,通常实际情况并不是这样,我们要把App用到的数据,封装在一个单独的类里,我们管这样的类,叫做Model。
在项目列表文件里,在UITableViewDemo文件夹上点击右键,选择New File...:
在弹出的对话框中,选择"Swift File":
点击"Next",给新建的文件起个名字,例如: EpisodeListItem,点击"Create"按钮:
然后,我们打开新创建的EpisodeListItem.swift文件,添加下面的代码:
class EpisodeListItem {
var title = ""
var finished = false
}
其中,title表示视频的标题,默认为空串,finished表示视频是否被看完的状态,默认是false。
然后,我们回到EpisodeListViewController,给它添加一个数组:
class EpisodeListViewController: UITableViewController {
var episodeListItems: Array<EpisodeListItem> = []
}
然后,我们添加一个初始化数组的方法:
class EpisodeListViewController: UITableViewController {
func getEpisodeListItemData() {
for i in 0..<10 {
let e = EpisodeListItem()
e.title = "Episode \(i)"
e.finished = Bool(i % 2) ? true : false
self.episodeListItems.append(e)
}
}
}
作为演示,我们总是把可以被2整除的项目定义为已经看过的,而每一个视频的标题被初始化成了"Episode 1, 2, 3..."这样的字符串。然后我们在viewDidLoad()方法里调用它:
class EpisodeListViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
getEpisodeListItemData()
}
}
接下来,我们来修改对应的data source方法,在获取了EpisodeItem对象之后,根据Cell的位置设置对应Model里的内容:
class EpisodeListViewController: UITableViewController {
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1\. Create the cell object
let cell = tableView.dequeueReusableCellWithIdentifier("EpisodeItem",
forIndexPath: indexPath)
// 2\. Get the label object
let label = cell.viewWithTag(1024) as! UILabel
// 3\. Set label text
label.text = self.episodeListItems[indexPath.row].title
// 4\. Set accessory type
cell.accessoryType =
self.episodeListItems[indexPath.row].finished ? .Checkmark : .None
return cell;
}
}
这次,我们没有硬编码UILabel的内容,而是根据cell在表格中的位置从episodeListItems中读取了对应的内容,并以此更新了UI中对应的部分。然后,按Command + R编译执行,我们就能看到对应的结果了:
这时,如果我们点一下其中一行,就会发现高亮不会自动取消,而是会一直保持在哪里,这和我们平时使用UITableView的直觉是不一样的,解决这个问题很简单,我们只要实现UITableViewDelegate中的一个方法就可以了。在EpisodeListViewController中添加下面的代码:
class EpisodeListViewController: UITableViewController {
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
这里,当Cell被选中的时候,iOS会通知tableView(, didSelectRowAtIndexPath)方法,在它的实现里,我们只是简单调用了tableView(, deselectRowAtIndexPath)方法,把选中的Cell重新变回未选中状态。完成之后,Command + R重新编译执行,这次,再选中Cell的时候,就有自动反选的效果了。