Xcode13下使用UINavigationBarAppearance修改导航栏颜色未同步到其他视图
问题原因
- iOS 15(配套Xcode 13)引入的
UINavigationBarAppearance体系中,UIAppearance全局配置仅对创建时间晚于配置修改时间的新视图生效,已经加载渲染到视图层级中的导航栏不会自动响应全局外观配置的更新,这和旧版barTintColor等属性修改后会触发全局重绘的逻辑不同。 - 当前仅手动更新了设置VC的
navigationItem外观,其他已经创建的VC/导航栏实例仍缓存了旧的外观配置,因此不会同步切换样式。
解决方案
仅需在setNavbarAttributes()方法的末尾新增全局已存在导航栏的主动刷新逻辑即可,无需逐个修改业务VC:
1. 调整全局导航栏配置类
class SetNarbar { static func setNavbarAttributes() { let theAppearance = UINavigationBarAppearance() theAppearance.configureWithOpaqueBackground() theAppearance.backgroundColor = Theme.current.navbarColor theAppearance.titleTextAttributes = [.foregroundColor: Theme.current.accentColor, .font: UIFont.systemFont(ofSize: gNavBarTitleTextSize, weight: .semibold)] // 更新全局外观,适配后续新创建的页面 UINavigationBar.appearance().standardAppearance = theAppearance UINavigationBar.appearance().scrollEdgeAppearance = theAppearance UINavigationBar.appearance().compactAppearance = theAppearance // 新增:刷新所有已经存在的导航栏实例 for scene in UIApplication.shared.connectedScenes { guard let windowScene = scene as? UIWindowScene else { continue } for window in windowScene.windows { updateNavigationBarInViewHierarchy(rootVC: window.rootViewController, appearance: theAppearance) } } } // 递归遍历视图层级更新所有导航栏配置 private static func updateNavigationBarInViewHierarchy(rootVC: UIViewController?, appearance: UINavigationBarAppearance) { guard let rootVC = rootVC else { return } // 处理当前控制器的导航栏 if let navVC = rootVC as? UINavigationController { navVC.navigationBar.standardAppearance = appearance navVC.navigationBar.scrollEdgeAppearance = appearance navVC.navigationBar.compactAppearance = appearance navVC.navigationBar.setNeedsLayout() navVC.navigationBar.layoutIfNeeded() // 遍历导航栈内所有控制器,清除单独设置的navigationItem外观(如果需要保留自定义配置可删除这段) for vc in navVC.viewControllers { vc.navigationItem.standardAppearance = nil vc.navigationItem.scrollEdgeAppearance = nil vc.navigationItem.compactAppearance = nil } } // 递归处理子控制器 for childVC in rootVC.children { updateNavigationBarInViewHierarchy(rootVC: childVC, appearance: appearance) } } }
2. 简化设置VC的主题更新逻辑
全局刷新逻辑已经覆盖了设置VC的导航栏配置,无需重复编写配置代码:
func updateThemeOnSettingsVC() { setNeedsStatusBarAppearanceUpdate() SetNarbar.setNavbarAttributes() }
如果部分业务VC有单独自定义的导航栏外观需求,不需要同步全局主题,只需要删除上述代码中清除navigationItem外观的遍历逻辑即可,不影响全局其他页面的同步效果。
内容的提问来源于stack exchange,提问作者user11004336
相关产品推荐
相关产品推荐

