更优雅地使用Static Cell
okra
8年前
<p>在项目开发中,经常会用到static cell来实现一些固定的列表界面(如:个人中心等),在static cell被点击时,如何判断被点击的cell是哪一个,有什么好的办法呢?</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/0d8c861db3b4a17216b2df8890c42cab.png"></p> <p style="text-align:center">个人中心</p> <p>如上界面,在storyboard下使用static cell实现起来不过一盏茶的功夫,每个cell对应的操作都不一样,那么如何确定点击的是哪一个cell呢?</p> <h2><strong>方法一. 使用indexPath</strong></h2> <p>似乎没什么好说的,使用indexPath来判断某一组某一行实在是太简单,如:</p> <pre> <code class="language-objectivec">if indexPath.section == 1 && indexPath.row == 1 { //我的粉丝 } if indexPath.section == 2 && indexPath.row == 1 { //关于我们 }</code></pre> <p>so easy 只需要2个判断就完成了,但这并不是什么好办法。如果经常使用static cell的同学很容易就看的出来,如果cell的行数发生了改变(如:添加cell,删除cell)又或者是cell的位置发生了改变(比如: 我的粉丝 与 我的关注 调换位置)这时候就需要重新编写判断条件,显而易见这不是好办法。</p> <h2><strong>方法二. 使用Tag</strong></h2> <p>为了解决indexPath的不足之处,很多人都会想到使用Tag,每个cell都绑定一个Tag值,这么一来无论是cell的行数发生改变,又或是cell的位置发生改变,都不会影响到判断条件,如:</p> <p><img src="https://simg.open-open.com/show/cc4cb5b91f3cd4c751927ea235a73a48.png"></p> <p style="text-align:center">给cell设置Tag值</p> <p>这时候添加新的cell只需要给新的cell绑定一个Tag,或者是cell的位置发生改变,并不会影响之前的写好的判断条件。</p> <pre> <code class="language-objectivec">guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return } switch cell.tag { case 101: print("新的好友") case 102: print("新手任务") case 201: print("我的关注") case 202: print("我的粉丝") // ... default: break }</code></pre> <p>但是,根据101,102,201...这些值无法直接体现出cell对应的内容(或操作),因此可以使用 enum 改进一下。如:</p> <pre> <code class="language-objectivec">//先定义一个enum enum CellName: Int { case NewFriends = 101 //101:第1组,第01行 case NewTask = 102 //102:第1组,第02行 case MyFollowing = 201 //201:第2组,第01行 case MyFans = 202 //... case Feedback = 301 //... case AboutUs = 302 //... case VersionInfo = 303 //... }</code></pre> <pre> <code class="language-objectivec">guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return } guard let cellName = CellName(rawValue: cell.tag) else { return } switch cellName { case .NewFriends: //新朋友 case .NewTaskL: //新任务 case .MyFollowing: //我的关注 case .MyFans: //我的粉丝 case .Feedback: //意见反馈 case .AboutUs: //关于我们 case .VersionInfo: //版本信息 }</code></pre> <p>这样看起来似乎还不错,但还是稍微有点不足,如果这时候需要在 新的好友 与 新手任务 中间插入一行 新手礼包 ,这时候cell的Tag值应该设置为多少呢?当然,只要是不重复的,随便设置一个 Tag=103 或者 Tag=999 都是可以的。但是这时候看起来就会些不协调了,如:</p> <pre> <code class="language-objectivec">enum CellName: Int { case NewFriends = 101 //101:第1组,第01行 case NovicePacks = 999 //999:第9组,第99行(但这竟然是第1组第2行) case NewTask = 102 //102:第1组,第02行(但这竟然是第3行) case MyFollowing = 201 //... case MyFans = 202 //... case Feedback = 301 //... case AboutUs = 302 //... case VersionInfo = 303 //... }</code></pre> <p>这样虽然也是可以的,也并没有影响之前的判断,使用 enum 之后一样显得很友好, <strong>但是</strong> ,如果cell的位置经常改变,产品经理脑子一热就要求添加一行新的cell,脑子一冷又要求删掉某一行cell,如此反复之后,cell的Tag就会毫无顺序可言,并不好维护。</p> <p>笔者虽不是处女座,但也无法接受这样的事情。</p> <h2><strong>方法三. 自定义一个标识(推荐使用,笔者最喜欢的方法)</strong></h2> <p>为了解决Tag反复修改之后变得无序的问题,反正迟早会变得无序,索性一开始就不考虑顺序问题。</p> <p>笔者想到的办法是,给cell扩展一个字段(叫: actionIdentifier )用于表示当前cell所代表的内容(或操作),且为了能在Storyboard中设置该值,因此加上 @IBInspectable 修饰,如:</p> <pre> <code class="language-objectivec">private var actionIdentifierKey: Void? public extension UITableViewCell { @IBInspectable var actionIdentifier: String { get { return objc_getAssociatedObject(self, &actionIdentifierKey) as? String ?? "" } set { objc_setAssociatedObject(self, &actionIdentifierKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } } }</code></pre> <p>这时候就可以在storyboard中这样操作,把Action identifier值设置为enum的值,如:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/8cea96b819f94c22150568bc86e57387.png"></p> <p style="text-align:center">设置ActionIdentifier值</p> <p>代码操作跟方法二几乎无异,如:</p> <pre> <code class="language-objectivec">//这里Int改成String enum ActionIdentifier: String { case NewFriends case NewTask case MyFollowing case MyFans case Feedback case AboutUs case VersionInfo }</code></pre> <pre> <code class="language-objectivec">guard let cell = tableView.cellForRowAtIndexPath(indexPath) else { return } guard let action = ActionIdentifier(rawValue: cell.actionIdentifier) else { return } switch action { case .NewFriends: case .NewTask: //... }</code></pre> <p>这时候看着就顺心多了...</p> <p>注意:文章中的代码段均是临时手写的,直接copy的话,不一定能编译通过。</p> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/3e5ac0e8d43e</p> <p> </p>