iPhone 12 mini 导航栏渐变背景图着色异常问题排查求助
异常触发原因
- 导航栏尺寸计算时机错误:在
viewDidLoad、viewWillAppear等生命周期节点调用时,导航栏还未完成自动布局,获取到的navigationBar.bounds是初始值,和最终渲染的真实尺寸不符。iPhone 12 mini的逻辑分辨率、状态栏高度参数和其余刘海屏机型存在差异,尺寸不匹配的问题在该机型上被触发。 - 状态栏高度获取方式不稳定:直接取
UIApplication.shared.windows[0]的状态栏高度,多场景(Scene)下第一个window不一定是当前页面所属的window,容易拿到错误的高度值。 - 渐变图片生成未适配Retina屏:使用
UIGraphicsBeginImageContext生成的是1倍分辨率图片,在2倍、3倍屏上会出现拉伸、尺寸错位问题,iPhone 12 mini的3倍屏缩放比例进一步放大了该问题。
修复方案
- 调整调用时机:将方法调用放到
viewDidLayoutSubviews中,确保导航栏布局完成后再计算尺寸;也可以监听导航栏的bounds属性变化,动态更新背景图。 - 修正状态栏高度获取逻辑:从当前视图所属的window中获取状态栏高度,避免取到错误window的参数。
- 适配Retina屏生成图片:改用
UIGraphicsBeginImageContextWithOptions生成对应分辨率的渐变图片。 - 适配新的导航栏API:优先使用iOS 13+推出的
UINavigationBarAppearance配置背景,兼容性更强。
修复后的参考代码:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() setNavGradiant() } func setNavGradiant(){ guard let navigationController = self.navigationController, let window = view.window, let statusBarHeight = window.windowScene?.statusBarManager?.statusBarFrame.height else { print("❇️♊️>>> \(#file) \(#line): guard let failed <<<") return } let gradientLayer = CAGradientLayer() var updatedFrame = navigationController.navigationBar.bounds updatedFrame.size.height += statusBarHeight gradientLayer.frame = updatedFrame gradientLayer.colors = [ #colorLiteral(red: 0.4392156899, green: 0.01176470611, blue: 0.1921568662, alpha: 1).cgColor, #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1).cgColor] gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0) gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0) // 适配Retina屏生成图片 UIGraphicsBeginImageContextWithOptions(gradientLayer.bounds.size, false, UIScreen.main.scale) guard let context = UIGraphicsGetCurrentContext() else { UIGraphicsEndImageContext() return } gradientLayer.render(in: context) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() // 适配新API,兼容性更好 if #available(iOS 13.0, *) { let appearance = UINavigationBarAppearance() appearance.backgroundImage = image appearance.titleTextAttributes = [.foregroundColor: #colorLiteral(red: 0.9579688907, green: 0.9579688907, blue: 0.9579688907, alpha: 1)] navigationController.navigationBar.standardAppearance = appearance navigationController.navigationBar.scrollEdgeAppearance = appearance } else { navigationController.navigationBar.setBackgroundImage(image, for: .default) navigationController.navigationBar.titleTextAttributes = [.foregroundColor: #colorLiteral(red: 0.9579688907, green: 0.9579688907, blue: 0.9579688907, alpha: 1)] } }
内容的提问来源于stack exchange,提问作者Ungrace
相关产品推荐
相关产品推荐

