You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:38:59