如何随滚动动态修改UITableView分区头 或为分区头添加按钮
实现方案
1. 优先推荐:不用自定义头部,直接给系统原生分区头加按钮
完全不需要重写viewForHeaderInSection写自定义头部,直接用tableView:willDisplayHeaderView:forSection:代理方法拿到系统渲染好的默认头部,在上面加按钮即可,原生的毛玻璃吸附效果会完全保留,不需要自己写任何效果逻辑:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section { UITableViewHeaderFooterView *sysHeader = (UITableViewHeaderFooterView *)view; // 避免复用时重复添加按钮 if (![sysHeader.contentView viewWithTag:999]) { UIButton *customBtn = [UIButton buttonWithType:UIButtonTypeSystem]; customBtn.tag = 999; [customBtn setTitle:@"自定义操作" forState:UIControlStateNormal]; customBtn.frame = CGRectMake(sysHeader.bounds.size.width - 70, 0, 60, sysHeader.bounds.size.height); customBtn.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight; // 必须加在contentView上,否则会遮挡系统背景层 [sysHeader.contentView addSubview:customBtn]; } }
这个方案零额外成本,所有系统默认行为(包括吸附时的薄毛玻璃切换、配色适配暗黑模式、布局边距)100%和原生一致。
2. 如果必须用自定义头部,完美复现原生毛玻璃效果
如果自定义头部有更复杂的布局需求,不要自己手动计算位置切换毛玻璃,iOS 15及以上系统直接用系统提供的背景配置,就能自动复现吸附时的毛玻璃切换效果:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UITableViewHeaderFooterView *customHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"CustomHeaderID"]; if (!customHeader) { customHeader = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:@"CustomHeaderID"]; // 在这里添加自定义的按钮、布局 } // 核心配置:和系统头部用完全一致的背景参数,自动处理吸附毛玻璃效果 customHeader.backgroundConfiguration = [UIBackgroundConfiguration listGroupedHeaderFooterConfiguration]; return customHeader; }
如果需要兼容iOS15以下版本,再手动实现吸附状态检测和毛玻璃切换:
- 在
scrollViewDidScroll:代理方法里遍历可见分区头,对比头部frame和表格顶部偏移量判断是否处于吸附状态 - 吸附时显示薄毛玻璃效果的
UIVisualEffectView(效果选UIBlurEffectStyleSystemThinMaterial),非吸附时隐藏即可
判断吸附状态的核心代码:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat topPinY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top; for (NSInteger section = 0; section < [self.tableView numberOfSections]; section++) { UIView *header = [self.tableView headerViewForSection:section]; if (!header) continue; CGRect headerRect = [self.tableView rectForHeaderInSection:section]; BOOL isPinned = CGRectGetMinY(headerRect) <= topPinY; // 根据isPinned状态切换毛玻璃显隐即可 } }
避坑提示:所有自定义子视图必须添加在
UITableViewHeaderFooterView的contentView上,直接添加到header视图本身会覆盖系统的背景渲染层,导致毛玻璃效果失效。


内容的提问来源于stack exchange,提问作者Grant Oganyan
相关产品推荐
相关产品推荐

