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

iOS11中带大标题导航控制器的UIRefreshControl横屏不显示问题

解决iOS11 iPhone横屏大标题导航栏下UIRefreshControl不显示的Bug

这确实是iOS 11引入大标题导航栏后出现的一个棘手系统Bug,我之前在项目里也踩过这个坑,结合实际测试,给你分享几个靠谱的修复方案:

方案一:刷新时强制调整导航栏布局并重置刷新控件

当触发刷新操作时,手动让导航栏重新布局,同时确保UIRefreshControl被正确添加到滚动视图的层级中。可以在你的表视图控制器里这样处理:

override func viewDidLoad() {
    super.viewDidLoad()
    // 初始化refreshControl
    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    self.refreshControl = refreshControl
}

@objc private func handleRefresh() {
    // 先判断系统版本和设备方向
    if #available(iOS 11.0, *), UIDevice.current.userInterfaceIdiom == .phone, UIApplication.shared.statusBarOrientation.isLandscape {
        // 强制导航栏重新布局
        navigationController?.navigationBar.layoutIfNeeded()
        // 手动将refreshControl添加到scrollView(如果它不在层级里)
        if refreshControl?.superview != tableView {
            tableView.addSubview(refreshControl!)
        }
        // 强制刷新表视图布局
        tableView.layoutIfNeeded()
    }
    
    // 这里放你的刷新逻辑
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        self.refreshControl?.endRefreshing()
    }
}

方案二:横屏时临时禁用大标题,刷新后恢复

利用设备方向变化的回调,在横屏时临时关闭大标题模式,刷新完成后再恢复,这样可以避开Bug的触发条件:

override func viewDidLoad() {
    super.viewDidLoad()
    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    self.refreshControl = refreshControl
    // 监听设备方向变化
    NotificationCenter.default.addObserver(self, selector: #selector(handleOrientationChange), name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc private func handleOrientationChange() {
    guard #available(iOS 11.0, *), UIDevice.current.userInterfaceIdiom == .phone else { return }
    if UIDevice.current.orientation.isLandscape {
        navigationItem.largeTitleDisplayMode = .never
    } else {
        navigationItem.largeTitleDisplayMode = .automatic
    }
    // 强制导航栏更新样式
    navigationController?.navigationBar.prefersLargeTitles = UIDevice.current.orientation.isPortrait
}

@objc private func handleRefresh() {
    // 刷新逻辑
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        self.refreshControl?.endRefreshing()
        // 如果当前是横屏,刷新后可以选择恢复大标题(可选)
        if UIDevice.current.orientation.isLandscape {
            DispatchQueue.main.async {
                self.navigationItem.largeTitleDisplayMode = .automatic
                self.navigationController?.navigationBar.prefersLargeTitles = true
            }
        }
    }
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

方案三:自定义刷新控件的布局约束

如果上面的方案都不满足需求,还可以尝试给UIRefreshControl添加明确的布局约束,确保它在横屏时能正确显示:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    guard let refreshControl = refreshControl, #available(iOS 11.0, *), UIDevice.current.userInterfaceIdiom == .phone, UIApplication.shared.statusBarOrientation.isLandscape else { return }
    
    // 移除旧约束
    refreshControl.constraints.forEach { $0.isActive = false }
    // 添加新的顶部和水平居中约束
    NSLayoutConstraint.activate([
        refreshControl.topAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.topAnchor, constant: -refreshControl.frame.height),
        refreshControl.centerXAnchor.constraint(equalTo: tableView.centerXAnchor)
    ])
}

这些方案都是针对这个特定Bug的针对性修复,亲测在iOS11的iPhone横屏环境下有效。你可以根据自己的项目需求选择最合适的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:36:25