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

如何在UINavigationBar实现随UITableView滚动的渐进式收缩动画?

实现导航栏随滚动渐变收缩的方案

你原有代码的核心问题是通过滚动方向触发固定时长的显隐动画,无法和滚动进度实时绑定,直接替换为以下逻辑即可:

第一步:新增所需属性

在当前类的头文件或者类扩展中添加以下属性:

/// 导航栏最大高度(包含状态栏)
@property (nonatomic, assign) CGFloat maxNavBarHeight;
/// 导航栏最小收缩高度
@property (nonatomic, assign) CGFloat minNavBarHeight;
/// 触发完整收缩效果需要滚动的距离,数值越大收缩节奏越慢
@property (nonatomic, assign) CGFloat scrollTriggerDistance;

第二步:初始化属性参数

在viewDidLoad中初始化配置,可根据自身需求调整数值:

- (void)viewDidLoad {
    [super viewDidLoad];
    // 动态获取当前设备状态栏高度
    CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
    // 普通导航栏总高度=状态栏高度+44,开启大标题的话改为 statusBarHeight + 96
    self.maxNavBarHeight = statusBarHeight + 44;
    // 最小高度可自定义,设为状态栏高度则收缩后仅保留状态栏,设为0则完全隐藏
    self.minNavBarHeight = statusBarHeight;
    // 滚动100pt距离完成整个收缩动画
    self.scrollTriggerDistance = 100;
}

第三步:重写scrollViewDidScroll逻辑

删除你原有滚动监听的代码,替换为实时绑定滚动偏移量的逻辑,不需要固定时长的动画即可实现跟手效果:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat offsetY = scrollView.contentOffset.y;
    // 下拉到顶部回弹时限制偏移量,避免异常拉伸
    if (offsetY < 0) offsetY = 0;
    
    // 计算收缩进度,范围固定在0~1之间,0=完全展开,1=完全收缩
    CGFloat progress = offsetY / self.scrollTriggerDistance;
    progress = MAX(0, MIN(1, progress));
    
    // 用transform调整导航栏位置实现收缩效果,比直接改frame性能更优
    CGFloat moveUpDistance = (self.maxNavBarHeight - self.minNavBarHeight) * progress;
    self.navigationController.navigationBar.transform = CGAffineTransformMakeTranslation(0, -moveUpDistance);
    
    // 同步调整导航栏透明度,不需要渐变的话可以删掉这部分
    self.navigationController.navigationBar.alpha = 1 - progress;
    // 同步调整导航栏上的按钮、标题等子控件透明度
    for (UIView *subview in self.navigationController.navigationBar.subviews) {
        subview.alpha = 1 - progress;
    }
}

第四步:页面退出时重置导航栏状态

避免跳转到其他页面时导航栏显示异常:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // 重置导航栏的形变和透明度
    self.navigationController.navigationBar.transform = CGAffineTransformIdentity;
    self.navigationController.navigationBar.alpha = 1;
}

注意事项

如果你是iOS 11及以上版本,并且使用系统自带的大标题导航栏,不需要手动写上述逻辑,只要开启self.navigationController.navigationBar.prefersLargeTitles = YES,同时将UITableView的顶部约束到父视图顶部而非安全区,系统会自动实现导航栏随滚动收缩的原生效果,流畅度更高。

内容的提问来源于stack exchange,提问作者stefanosn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:24:05