• IOS-更优雅地使用Static Cell


    更优雅地使用Static Cell

    在项目开发中,经常会用到static cell来实现一些固定的列表界面(如:个人中心等),在static cell被点击时,如何判断被点击的cell是哪一个,有什么好的办法呢?


    个人中心

    如上界面,在storyboard下使用static cell实现起来不过一盏茶的功夫,每个cell对应的操作都不一样,那么如何确定点击的是哪一个cell呢?

    方法一. 使用indexPath

    似乎没什么好说的,使用indexPath来判断某一组某一行实在是太简单,如:

    1 if indexPath.section == 1 && indexPath.row == 1 {
    2      //我的粉丝
    3 }
    4 if indexPath.section == 2 && indexPath.row == 1 {
    5     //关于我们
    6 }

    so easy 只需要2个判断就完成了,但这并不是什么好办法。如果经常使用static cell的同学很容易就看的出来,如果cell的行数发生了改变(如:添加cell,删除cell)又或者是cell的位置发生了改变(比如:我的粉丝我的关注调换位置)这时候就需要重新编写判断条件,显而易见这不是好办法。

    方法二. 使用Tag

    为了解决indexPath的不足之处,很多人都会想到使用Tag,每个cell都绑定一个Tag值,这么一来无论是cell的行数发生改变,又或是cell的位置发生改变,都不会影响到判断条件,如:


                                                      给cell设置Tag值


    这时候添加新的cell只需要给新的cell绑定一个Tag,或者是cell的位置发生改变,并不会影响之前的写好的判断条件。

    1 guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return }
    2   switch cell.tag {
    3     case 101:   print("新的好友")
    4     case 102:   print("新手任务")
    5     case 201:   print("我的关注")
    6     case 202:   print("我的粉丝")
    7     // ...
    8     default:    break
    9 }

    但是,根据101,102,201...这些值无法直接体现出cell对应的内容(或操作),因此可以使用enum改进一下。如:

     1 //先定义一个enum
     2 enum CellName: Int {
     3     case NewFriends     = 101  //101:第1组,第01行
     4     case NewTask        = 102  //102:第1组,第02行
     5     case MyFollowing    = 201  //201:第2组,第01行
     6     case MyFans         = 202  //...
     7     case Feedback       = 301  //...
     8     case AboutUs        = 302  //...
     9     case VersionInfo    = 303  //...
    10 }
     1 guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return }
     2 guard let cellName = CellName(rawValue: cell.tag) else { return }
     3 switch cellName {
     4   case .NewFriends:       //新朋友
     5   case .NewTaskL:         //新任务
     6   case .MyFollowing:      //我的关注
     7   case .MyFans:           //我的粉丝
     8   case .Feedback:         //意见反馈
     9   case .AboutUs:          //关于我们
    10   case .VersionInfo:      //版本信息
    11 }

    这样看起来似乎还不错,但还是稍微有点不足,如果这时候需要在新的好友新手任务中间插入一行新手礼包,这时候cell的Tag值应该设置为多少呢?当然,只要是不重复的,随便设置一个Tag=103或者Tag=999都是可以的。但是这时候看起来就会些不协调了,如:

     1 enum CellName: Int {
     2     case NewFriends     = 101  //101:第1组,第01行
     3     case NovicePacks    = 999  //999:第9组,第99行(但这竟然是第1组第2行)
     4     case NewTask        = 102  //102:第1组,第02行(但这竟然是第3行)
     5     case MyFollowing    = 201  //...
     6     case MyFans         = 202  //...
     7     case Feedback       = 301  //...
     8     case AboutUs        = 302  //...
     9     case VersionInfo    = 303  //...
    10 }

    这样虽然也是可以的,也并没有影响之前的判断,使用enum之后一样显得很友好,但是,如果cell的位置经常改变,产品经理脑子一热就要求添加一行新的cell,脑子一冷又要求删掉某一行cell,如此反复之后,cell的Tag就会毫无顺序可言,并不好维护。
    笔者虽不是处女座,但也无法接受这样的事情。

    方法三. 自定义一个标识(推荐使用,笔者最喜欢的方法)

    为了解决Tag反复修改之后变得无序的问题,反正迟早会变得无序,索性一开始就不考虑顺序问题。
    笔者想到的办法是,给cell扩展一个字段(叫:actionIdentifier)用于表示当前cell所代表的内容(或操作),且为了能在Storyboard中设置该值,因此加上@IBInspectable修饰,如:

     1 private var actionIdentifierKey: Void?
     2 
     3 public extension UITableViewCell {
     4 
     5     @IBInspectable var actionIdentifier: String {
     6         get {
     7             return objc_getAssociatedObject(self, &actionIdentifierKey) as? String ?? ""
     8         }
     9         set {
    10             objc_setAssociatedObject(self, &actionIdentifierKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
    11         }
    12     }
    13 
    14 }

    这时候就可以在storyboard中这样操作,把Action identifier值设置为enum的值,如:


                                                 设置ActionIdentifier值

    代码操作跟方法二几乎无异,如:

     1 //这里Int改成String
     2 enum ActionIdentifier: String {
     3     case NewFriends
     4     case NewTask
     5     case MyFollowing
     6     case MyFans
     7     case Feedback
     8     case AboutUs
     9     case VersionInfo
    10 }
    1 guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return }
    2 guard let action = ActionIdentifier(rawValue: cell.actionIdentifier) else { return }
    3 switch action {
    4   case .NewFriends:
    5   case .NewTask:
    6   //...
    7 }

    这时候看着就顺心多了...
    注意:文章中的代码段均是临时手写的,直接copy的话,不一定能编译通过。



    文/Chakery(简书作者)
    原文链接:http://www.jianshu.com/p/3e5ac0e8d43e
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 相关阅读:
    java后台对上传的图片进行压缩
    Reflections框架,类扫描工具
    commons-httpclient和org.apache.httpcomponents的区别
    sql里面插入语句insert后面的values关键字可省略
    Callable接口、Runable接口、Future接口
    Java多线程之Callable接口的实现
    说说Runnable与Callable
    论坛贴吧问题:如何终止运行时间超时的线程
    使用Future停止超时任务
    spring的@Transactional注解详细用法
  • 原文地址:https://www.cnblogs.com/oc-bowen/p/5884161.html
Copyright © 2020-2023  润新知