UITableView指定单元格折叠/展开问题:点击头部按钮后位置未调整
解决UITableView分类折叠后下方section不上移的问题
你的问题出在直接隐藏cell的方式不符合UITableView的布局逻辑——你只是让cell看不见,但tableView依然会为这些cell预留高度,所以dog的section自然不会上移,空白区域就留出来了。
正确的做法是通过修改数据源+刷新tableView来实现折叠/展开,让系统自动重新计算布局,具体步骤和代码如下:
1. 核心思路
- 维护一个状态变量,记录每个分类(section)的展开/折叠状态。
- 在数据源方法中,根据当前section的状态返回对应行数:折叠时返回0行,展开时返回正常行数。
- 点击分类按钮时,切换对应section的状态,然后刷新该section,让tableView自动调整布局。
2. 具体实现代码
第一步:定义状态和数据变量
在你的ViewController的.m文件中添加以下属性:
@property (nonatomic, strong) NSMutableDictionary *sectionExpandedStates; // 记录每个section的展开状态 @property (nonatomic, strong) NSArray *categoryList; // 分类列表:cat、dog @property (nonatomic, strong) NSDictionary *categoryData; // 每个分类对应的列表数据
第二步:初始化数据和状态
在viewDidLoad中初始化:
- (void)viewDidLoad { [super viewDidLoad]; // 初始化分类和对应的数据 self.categoryList = @[@"cat", @"dog"]; self.categoryData = @{@"cat": @[@"橘猫", @"英短", @"布偶"], @"dog": @[@"柴犬", @"柯基", @"边牧"]}; // 初始化展开状态:默认全部展开 self.sectionExpandedStates = [NSMutableDictionary dictionary]; for (NSString *category in self.categoryList) { self.sectionExpandedStates[category] = @YES; } // 设置tableView的代理和数据源 self.accountBalanceTableView.delegate = self; self.accountBalanceTableView.dataSource = self; }
第三步:实现UITableView数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.categoryList.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSString *currentCategory = self.categoryList[section]; BOOL isExpanded = [self.sectionExpandedStates[currentCategory] boolValue]; // 折叠时返回0行,tableView就不会为该section预留行高 return isExpanded ? self.categoryData[currentCategory].count : 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCellID" forIndexPath:indexPath]; NSString *category = self.categoryList[indexPath.section]; cell.textLabel.text = self.categoryData[category][indexPath.row]; return cell; }
第四步:实现section头部视图和点击事件
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 50)]; headerView.backgroundColor = [UIColor lightGrayColor]; // 创建分类按钮 NSString *category = self.categoryList[section]; UIButton *categoryBtn = [UIButton buttonWithType:UIButtonTypeSystem]; categoryBtn.frame = headerView.bounds; [categoryBtn setTitle:category forState:UIControlStateNormal]; [categoryBtn addTarget:self action:@selector(onCategoryBtnTapped:) forControlEvents:UIControlEventTouchUpInside]; categoryBtn.tag = section; // 用tag标记当前section索引 [headerView addSubview:categoryBtn]; return headerView; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 50; // 设置头部高度 }
第五步:处理按钮点击,切换折叠/展开状态
- (void)onCategoryBtnTapped:(UIButton *)sender { NSInteger section = sender.tag; NSString *category = self.categoryList[section]; // 切换当前section的展开状态 BOOL currentState = [self.sectionExpandedStates[category] boolValue]; self.sectionExpandedStates[category] = @(!currentState); // 刷新对应的section,自带动画效果 [self.accountBalanceTableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic]; }
为什么这个方案可行?
UITableView的布局完全依赖于数据源返回的行数和高度。当你把折叠section的行数设为0时,tableView会自动重新计算整个列表的高度,把下方的section(dog)上移,不会留下任何空白,同时还能通过reloadSections实现流畅的折叠/展开动画。
内容的提问来源于stack exchange,提问作者KikX
相关产品推荐
相关产品推荐

