You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS 11大标题模式下点击状态栏滚动到顶部异常求助

iOS 11大标题模式下点击状态栏滚动过度的问题修复

我之前也碰到过这个iOS 11大标题模式下的滚动bug,确实挺影响体验——不管是UITableView还是UIScrollView,只要开了大标题,点击状态栏滚到顶部时都会出现导航栏高度异常、甚至下拉刷新控件状态错乱的问题,轻触屏幕或小幅滚动才能恢复。这其实是iOS 11初期版本中,大标题动态切换逻辑和scrollsToTop交互的一个已知bug,下面给你几个可行的解决方案:

问题复现步骤

  • 创建带导航控制器的新项目,ViewController内添加UITableView
  • 设置导航控制器偏好大标题(navigationController?.navigationBar.prefersLargeTitles = true),关闭半透明(navigationController?.navigationBar.isTranslucent = false),设置ViewController标题
  • 给TableView添加约束使其贴合ViewController边缘
  • 绑定TableView的Outlet,实现代理并设置足够多行数据(比如100行)
  • 启动应用后向下滚动,让大标题收缩为普通标题,再点击状态栏触发滚动到顶部,即可看到异常

解决方案

方案1:拦截默认滚动行为,手动控制滚动位置

通过UIScrollViewDelegatescrollViewShouldScrollToTop方法,拦截系统默认的滚动到顶部行为,手动滚动到正确的位置,确保导航栏能正确切换状态:

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    // ... 原有代理方法保持不变 ...
    
    func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
        // 禁用默认滚动,手动动画滚动到正确的顶部位置
        UIView.animate(withDuration: 0.3) {
            // 使用adjustedContentInset来计算正确的偏移量,适配导航栏高度
            scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.adjustedContentInset.top), animated: false)
        }
        return false
    }
}

方案2:延迟滚动,给系统留足导航栏状态切换时间

如果方案1的动画不够顺滑,可以尝试给系统一点时间处理大标题的收缩/展开逻辑,再执行滚动:

func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        scrollView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
    }
    return false
}

方案3:升级到iOS 12及以上版本

这个bug在iOS 12正式版中已经被苹果官方修复,如果你的应用部署目标可以提升到iOS 12+,直接升级系统版本就能彻底解决这个问题,不需要额外的代码修改。

补充说明

如果你的TableView添加了UIRefreshControl,可以在刷新控件的valueChanged事件中额外检查滚动位置,确保刷新状态正常:

@objc func handleRefresh() {
    // 刷新逻辑...
    
    // 刷新完成后确保滚动位置正确
    DispatchQueue.main.async {
        self.tableView.setContentOffset(CGPoint(x: 0, y: -self.tableView.adjustedContentInset.top), animated: true)
    }
}

内容的提问来源于stack exchange,提问作者Bram-N

火山引擎 最新活动