定义Model并且添加UITableView事件处理

我们实现了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的时候,就有自动反选的效果了。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章