iOS Swift:多分区TableView内嵌CollectionView代理设置问题
嘿,这个场景我太熟悉了——多分区TableView每行嵌CollectionView,代理关联的时候很容易搞混对吧?用collectionView.tag来绑定对应的TableView分区和行绝对是个简单高效的方案,我给你一步步说清楚怎么做👇
1. 给每个CollectionView设置唯一的Tag值
核心思路是把TableView的section和row信息编码成一个Int类型的tag,因为Int在iOS里是64位的,用位运算就能完美把两个值塞进一个tag里,不会冲突。
在TableView的cellForRowAt(Swift)或tableView:cellForRowAtIndexPath:(OC)方法里,复用TableViewCell的时候给内嵌的CollectionView设置tag:
Swift 代码示例
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell // 把section左移16位,再和row做或运算,生成唯一tag // 左移16位是因为row的最大值几乎不会超过65535(2^16),不会和section的信息重叠 cell.collectionView.tag = (indexPath.section << 16) | indexPath.row // 绑定代理和数据源 cell.collectionView.delegate = self cell.collectionView.dataSource = self // 刷新CollectionView数据 cell.collectionView.reloadData() return cell }
OC 代码示例
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TableViewCell" forIndexPath:indexPath]; // 编码section和row到tag中 cell.collectionView.tag = (indexPath.section << 16) | indexPath.row; cell.collectionView.delegate = self; cell.collectionView.dataSource = self; [cell.collectionView reloadData]; return cell; }
2. 从Tag中解析出对应的TableView分区和行
当你在CollectionView的代理方法(比如点击事件、cell创建)里需要知道它属于TableView的哪一行哪一区时,把tag解码出来就行:
Swift 代码示例(以点击事件为例)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 右移16位取出section信息 let section = collectionView.tag >> 16 // 和0xFFFF做与运算,取出低16位的row信息 let row = collectionView.tag & 0xFFFF // 生成对应的TableView indexPath let tableViewIndexPath = IndexPath(row: row, section: section) // 接下来就可以做你需要的操作啦,比如获取对应的TableViewCell,或者更新数据 print("点击了TableView第\(section)分区第\(row)行里的CollectionView第\(indexPath.item)项") }
OC 代码示例(以点击事件为例)
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { // 解码section NSInteger section = collectionView.tag >> 16; // 解码row NSInteger row = collectionView.tag & 0xFFFF; NSIndexPath *tableViewIndexPath = [NSIndexPath indexPathForRow:row inSection:section]; NSLog(@"点击了TableView第%ld分区第%ld行里的CollectionView第%ld项", section, row, indexPath.item); }
额外提醒
- 如果你的TableView每行数量特别多(超过65535,这种情况几乎不会出现),可以调整位运算的位数,比如把section左移20位,这样row最多能到1048575,完全够用。
- 一定要在复用TableViewCell的时候重新设置tag和代理,避免复用导致的tag错乱问题。
- 如果你的CollectionView是在xib/storyboard里创建的,记得把初始tag设为0,避免和我们自定义的tag冲突。
内容的提问来源于stack exchange,提问作者Andre
相关产品推荐
相关产品推荐

