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
相关产品推荐
相关产品推荐

