更加 Swift 化的 Collection View 和 Table View Cells

更加 Swift 化的 Collection View 和 Table View Cells,第1张

概述作者:Jameson Quave,原文链接,原文日期:2015-12-28 译者:CMB;校对:Cee;定稿:千叶知风 这是一个常见的场景:你有一个 tableView 或者一个 collectionView,并且里面含有大量不同种类的内容。你想做到基于不同种类的内容而展示不一样的 cell ,而且这些 cell 都混合在同一个部件里(原谅我站在艺术的角度去设计),它看起来就如下图所示: 在 Ob

作者:Jameson Quave,原文链接,原文日期:2015-12-28
译者:CMB;校对:Cee;定稿:千叶知风

这是一个常见的场景:你有一个 tableVIEw 或者一个 collectionVIEw,并且里面含有大量不同种类的内容。你想做到基于不同种类的内容而展示不一样的 cell ,而且这些 cell 都混合在同一个部件里(原谅我站在艺术的角度去设计),它看起来就如下图所示:

在 Objective-C 中,最典型就是使用 NSArray 来记录 collectionVIEw 的数据源,然后通过对比每个数据源的类型后再对 cell 进行 *** 作,现在看来这种方式是特别不方便的。

objective-c- (UICollectionVIEwCell *)collectionVIEw:(UICollectionVIEw *)collectionVIEw cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionVIEwCell *cell = [collectionVIEw dequeueReusableCellWithReuseIDentifIEr:@"IDentifIEr" forIndexPath:indexPath];     ID record = self.records[indexPath.row];     if([record isKindOfClass:[PlaythroughItem class]]) {        // ...    }    else if([record isKindOfClass:[RevIEwItem class]]) {        // ...    }    else if([record isKindOfClass:[TrailerItem class]]) {        // ...    }     return cell;}

战栗吧

这并不是种类型安全的方法,尽管我们在 Objective-C 中这么使用这段代码已经不足为奇了。在 Swift 中,有更加好的替换方式去解决上述问题,那就是使用枚举的 case 情况来为不同类型的项做标识,然后通过这些 case 就可以找到我们所需要的项。让我们看看下面的例子。

例子

这是一个我正在写的休闲娱乐类 App 中需要一些不同新闻类型的 cell 的代码:

enum NewsItem {  case Trailer(index: Int)  case RevIEw(index: Int)  case Playthrough(index: Int)}

索引仅仅是用来记录数据在数据库中位置的方法。我们采取这种索引的方法来标识所需数据在 collectionVIEw 中位置的展示。对于特定视频,我们就不需要其所关联的所有数据了,所需要的信息仅需要在 collectionVIEw 中的 cell 点击之后才去通过索引获取。

我们有一个简单的 collectionVIEw,它里面含有三个自定义的 cell 。我使用 NewsFeed.swift 文件作为这个新闻 collectionVIEw 的主要数据源。我特别感兴趣的是 cellForItemAtIndexPath 方法,通过 NewsItem 枚举来区分 record 的类型,从而产生相对应的 cell

func collectionVIEw(collectionVIEw: UICollectionVIEw,cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionVIEwCell {    let record = records[indexPath.row]     switch(record) {     case .Playthrough(let index):         let cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("PlaythroughCell",forIndexPath: indexPath) as! PlaythroughCollectionVIEwCell        let playthrough = MediaDB.playthroughAtIndex(index)        cell.TitleLabel.text = playthrough.Title        cell.lengthLabel.text = playthrough.length.prettyTime        return cell     case .RevIEw(let index):        let cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("RevIEwCell",forIndexPath: indexPath) as! RevIEwCollectionVIEwCell        let revIEw = MediaDB.revIEwAtIndex(index)        cell.ratingLabel.text = "\(revIEw.rating) out of 10"        cell.TitleLabel.text = revIEw.Title        return cell     case .Trailer(let index):        let cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("TrailerCell",forIndexPath: indexPath) as! TrailerCollectionVIEwCell        let trailer = MediaDB.trailerAtIndex(index)        cell.TitleLabel.text = trailer.Title        cell.lengthLabel.text = trailer.length.prettyTime        return cell    }}

上面的代码可以清晰看出,record 可以表示为 NewsItem 枚举里三个 case 中任意一个:

enum NewsItem {  case Trailer(index: Int)  case RevIEw(index: Int)  case Playthrough(index: Int)}

当我们想在 collectionVIEw 中展示一个 cell 的时候,我们可以通过相关的索引值去找到数据库中所对应的那一项。

这段代码让我觉得很不舒服。有许多重复代码,尤其是 switch 显得非常笨重,在每个 case 中都做了太多事情。

但是,如果我创建了一个可以用在 collectionVIEw cell 上的处理任何数据源的协议呢?鉴于每个视图(vIEw)都并不相同,所以我不希望这个协议在模型(model)中使用。但我可以在特定的 collectionVIEw cell 的子类上使用它。

所以,我创建了一个叫做 NewsCellPresentable 协议,这个协议被自定义的 collectionVIEw cell 所扩展:

protocol NewsCellPresentable {    func configureForIndex(index: Int)} extension PlaythroughCollectionVIEwCell: NewsCellPresentable {    func configureForIndex(index: Int) {        let playthrough = MediaDB.playthroughAtIndex(index)        self.TitleLabel.text = playthrough.Title        self.lengthLabel.text = playthrough.length.prettyTime    }}extension RevIEwCollectionVIEwCell: NewsCellPresentable {    func configureForIndex(index: Int) {        let revIEw = MediaDB.revIEwAtIndex(index)        self.TitleLabel.text = revIEw.Title        self.ratingLabel.text = "\(revIEw.rating) out of 10"    }}extension TrailerCollectionVIEwCell: NewsCellPresentable {    func configureForIndex(index: Int) {        let trailer = MediaDB.trailerAtIndex(index)        self.TitleLabel.text = trailer.Title        self.lengthLabel.text = trailer.length.prettyTime    }}

这样写看起来已经很简洁明了了。现在我们回到 cellForItemAtIndexPath 方法中对代码进行修改,修改后如下所示:

func collectionVIEw(collectionVIEw: UICollectionVIEw,cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionVIEwCell {    let record = records[indexPath.row]     var cell: NewsCellPresentable    switch(record) {     case .Playthrough(let index):        cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("PlaythroughCell",forIndexPath: indexPath) as! PlaythroughCollectionVIEwCell        cell.configureForIndex(index)     case .RevIEw(let index):        cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("RevIEwCell",forIndexPath: indexPath) as! RevIEwCollectionVIEwCell        cell.configureForIndex(index)     case .Trailer(let index):        cell = collectionVIEw.dequeueReusableCellWithReuseIDentifIEr("TrailerCell",forIndexPath: indexPath) as! TrailerCollectionVIEwCell        cell.configureForIndex(index)    }     return (cell as! MediaCollectionVIEwCell)}

你觉得这种方法怎么样?这是一种更为简洁的方法吗?如果你有其它不同的实现方法,可以直接在文章下面留言给我,或者在 Twitter 上留言给我,我的用户名是 @jquave,希望可以一起交流学习。

附言

如果你没有数据库底层代码,但又想写出和我例子一样的实例,你可以参照下列代码:

class MediaDB {    class func TitleForRecord(index: Int) -> String {        return "Title!!"    }    class func trailerAtIndex(index: Int) -> Trailer {        return Trailer()    }    class func revIEwAtIndex(index: Int) -> RevIEw {        return RevIEw()    }    class func playthroughAtIndex(index: Int) -> Playthrough {        return Playthrough()    }} struct Trailer {    let Title = "Trailer Title"    let length = 190} struct RevIEw {    let Title = "RevIEw Title"    let rating = 4} struct Playthrough {    let Title = "Playthrough Title"    let length = 9365}  enum NewsItem {    case Trailer(index: Int)    case RevIEw(index: Int)    case Playthrough(index: Int)}

就个人而言,在写后端服务和接口之前,我总会做静态值的存根。这样会使得项目更容易迭代。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。

总结

以上是内存溢出为你收集整理的更加 Swift 化的 Collection View 和 Table View Cells全部内容,希望文章能够帮你解决更加 Swift 化的 Collection View 和 Table View Cells所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1090956.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-27
下一篇2022-05-27

发表评论

登录后才能评论

评论列表(0条)

    保存