点击表格单元格中集合视图项时,如何获取对应表格行索引?
这个场景太常见了!我之前做类似的横向滚动列表嵌套时也卡过,给你分享几个实用的解决办法,挑适合你的来:
方案一:代理模式(最符合iOS设计规范)
这是iOS组件间通信的标准玩法,步骤清晰扩展性强:
- 在
TableCell.h里定义代理协议,用来传递点击事件和索引信息:
@protocol TableCellCollectionViewDelegate <NSObject> - (void)tableCell:(TableCell *)cell didSelectCollectionItemAtIndexPath:(NSIndexPath *)collectionIndexPath tableViewRow:(NSInteger)row; @end @interface TableCell : UITableViewCell @property (nonatomic, weak) id<TableCellCollectionViewDelegate> collectionDelegate; @property (nonatomic, assign) NSInteger tableViewRow; // 保存当前cell所在的tableView行号 @end
- 在
TableCell.m的点击方法里调用代理传递数据:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if ([self.collectionDelegate respondsToSelector:@selector(tableCell:didSelectCollectionItemAtIndexPath:tableViewRow:)]) { [self.collectionDelegate tableCell:self didSelectCollectionItemAtIndexPath:indexPath tableViewRow:self.tableViewRow]; } }
- 在ViewController的
tableView:cellForRowAtIndexPath:里给cell设置代理和行号:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TableCell" forIndexPath:indexPath]; cell.collectionDelegate = self; cell.tableViewRow = indexPath.row; // 其他cell配置逻辑 return cell; }
- 最后在ViewController实现代理方法,就能拿到需要的索引了:
#pragma mark - TableCellCollectionViewDelegate - (void)tableCell:(TableCell *)cell didSelectCollectionItemAtIndexPath:(NSIndexPath *)collectionIndexPath tableViewRow:(NSInteger)row { NSLog(@"点击了第%ld行TableView里的第%ld个CollectionView项", (long)row, (long)collectionIndexPath.item); // 这里处理你的业务逻辑 }
方案二:Block回调(代码更简洁轻量)
如果不想写代理协议,用Block是更省事的选择:
- 在
TableCell.h里定义Block属性:
@interface TableCell : UITableViewCell @property (nonatomic, copy) void(^collectionItemSelectedBlock)(NSInteger tableViewRow, NSIndexPath *collectionIndexPath); @property (nonatomic, assign) NSInteger tableViewRow; @end
- 在
TableCell.m的点击方法里触发Block:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (self.collectionItemSelectedBlock) { self.collectionItemSelectedBlock(self.tableViewRow, indexPath); } }
- 在ViewController的
cellForRow里给Block赋值(注意用弱引用避免循环引用):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TableCell" forIndexPath:indexPath]; __weak typeof(self) weakSelf = self; cell.collectionItemSelectedBlock = ^(NSInteger tableViewRow, NSIndexPath *collectionIndexPath) { NSLog(@"点击了第%ld行TableView里的第%ld个CollectionView项", (long)tableViewRow, (long)collectionIndexPath.item); // 用weakSelf处理业务逻辑 }; cell.tableViewRow = indexPath.row; return cell; }
方案三:通过视图层级查找(无需提前传值)
这种方法不需要给cell加额外属性,直接通过视图结构往上找对应的TableCell:
在TableCell.m的点击方法里写:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { // 递归查找父视图中的TableCell UIView *currentView = collectionView; while (currentView && ![currentView isKindOfClass:[UITableViewCell class]]) { currentView = currentView.superview; } if ([currentView isKindOfClass:[UITableViewCell class]]) { UITableViewCell *tableCell = (UITableViewCell *)currentView; UITableView *tableView = (UITableView *)tableCell.superview; NSIndexPath *tableIndexPath = [tableView indexPathForCell:tableCell]; NSInteger row = tableIndexPath.row; NSLog(@"点击了第%ld行TableView里的第%ld个CollectionView项", (long)row, (long)indexPath.item); // 处理业务逻辑 } }
⚠️ 注意:这种方法依赖视图层级结构,如果你的CollectionView嵌套在多层容器里,要确保递归能找到TableCell;后续修改cell布局时,可能需要调整查找逻辑。
方案对比和推荐
- 如果cell和ViewController之间需要多交互(比如刷新数据、传递状态),代理模式最稳妥,扩展性强;
- 如果只是简单的点击回调,Block回调代码更简洁,可读性高;
- 视图层级查找适合不想给cell加额外属性的场景,但稳定性稍差,不推荐在复杂布局中使用。
内容的提问来源于stack exchange,提问作者Zeen
相关产品推荐
相关产品推荐

