Xcode13 iOS15下UINavigationBar不同状态阴影分离显示实现咨询
问题根因
iOS15 对 UINavigationBar 的渲染逻辑做了两点调整,是导致问题的核心原因:
- 当
UINavigationBarAppearance的shadowColor属性被显式设置为非nil值时,系统会优先使用该颜色渲染阴影,直接忽略自定义的shadowImage配置 scrollEdgeAppearance和standardAppearance切换时,系统默认仅更新背景色相关属性,不会主动刷新阴影图层,导致自定义阴影不生效
修正方案
1. 修正Appearance配置
核心调整点:需要使用自定义shadowImage时,将shadowColor设为nil,避免覆盖自定义图片的显示。
修正后的完整代码如下:
class MyViewController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() // 全局开启大标题显示 navigationBar.prefersLargeTitles = true if #available(iOS 13.0, *) { // 标准标题状态配置 let standard = UINavigationBarAppearance() standard.configureWithOpaqueBackground() standard.backgroundColor = .systemBlue // 替换为你自己的渐变阴影图片即可 standard.shadowImage = UIImage(color: .black) // 关键配置:设置为nil,保证自定义shadowImage生效 standard.shadowColor = nil navigationBar.standardAppearance = standard // 大标题(滚动边缘)状态配置 let scroll = UINavigationBarAppearance() scroll.configureWithOpaqueBackground() scroll.backgroundColor = .systemRed // 空图片实现隐藏阴影 scroll.shadowImage = UIImage() scroll.shadowColor = nil navigationBar.scrollEdgeAppearance = scroll // iOS15+ 额外配置,保证紧凑模式、push/pop 时样式一致 if #available(iOS 15.0, *) { navigationBar.compactAppearance = standard } } else { // iOS13以下的兼容逻辑可在此补充 navigationBar.barTintColor = .systemBlue navigationBar.shadowImage = UIImage(color: .black) } } } // 你用到的UIImage扩展,生成纯色图片(仅作示例,可保留你自己的实现) extension UIImage { convenience init(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) { UIGraphicsBeginImageContextWithOptions(size, false, 0) color.setFill() UIRectFill(CGRect(origin: .zero, size: size)) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: image!.cgImage!) } }
2. 异常情况补充处理
如果按照上述配置后切换状态时阴影仍不刷新,可以在当前页面的UIScrollView代理方法中主动触发导航栏刷新:
// 对应视图控制器中实现scrollView代理方法 func scrollViewDidScroll(_ scrollView: UIScrollView) { navigationBar.setNeedsLayout() navigationBar.layoutIfNeeded() }
验证点
- 标准标题状态下可正常显示自定义渐变阴影图片
- 大标题状态下阴影完全隐藏
- iOS14、iOS15+系统表现一致
内容的提问来源于stack exchange,提问作者이동근
相关产品推荐
相关产品推荐

