iOS13.0+版本导航栏添加渐变后UIBarButtonItem隐藏问题如何解决
问题原因
- CAGradientLayer初始化逻辑错误:原代码中
let gradient = CAGradientLayer(layer: colors)是错误用法,该初始化方法作用是复制已有Layer的属性,传入UIColor数组会导致渐变层颜色配置完全失效,生成的背景图不符合预期,极易出现和按钮文字撞色的情况,导致文字视觉上被“隐藏”。 - 未配置UIBarButtonItem的文字样式:仅设置了导航栏标题的文字属性,没有配置UIBarButtonItem的普通/高亮状态文字颜色,iOS13+下UIBarButtonItem默认文字颜色会跟随系统样式适配,和你使用的橙红渐变背景色重合时,就会出现全屏状态下看不见、侧滑半透明状态下可见的现象。
- 渐变图片生成时机错误:配置appearance时直接取当前navigationBar的bounds生成图片,此时导航栏还未完成布局,bounds尺寸错误,生成的背景图片拉伸异常也可能遮挡按钮。
- 全局样式优先级问题:页面内直接设置全局
UINavigationBar.appearance(),如果当前导航控制器或页面有单独的导航栏配置,会覆盖全局样式,导致按钮样式异常。
修复方案
1. 修复渐变图片生成逻辑
修正CAGradientLayer初始化错误,改为传入size参数避免布局未完成导致的尺寸问题:
extension UIImage { static func getGradientImage(withColors colors: [UIColor], size: CGSize) -> UIImage { let gradient = CAGradientLayer() // 需把UIColor转换为CGColor gradient.colors = colors.map{ $0.cgColor } gradient.frame = CGRect(origin: .zero, size: size) gradient.locations = [0.0, 1.0] gradient.startPoint = CGPoint(x: 0.0, y: 0.5) gradient.endPoint = CGPoint(x: 1.0, y: 0.5) return UIImage.image(from: gradient) ?? UIImage() } static func image(from layer: CALayer) -> UIImage? { UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, UIScreen.main.scale) defer { UIGraphicsEndImageContext() } guard let context = UIGraphicsGetCurrentContext() else { return nil } layer.render(in: context) return UIGraphicsGetImageFromCurrentImageContext() } }
2. 补充UIBarButtonItem样式配置
给UINavigationBarAppearance增加按钮样式配置,直接给当前导航栏设置样式替代全局配置,同时显式指定tintColor:
if #available(iOS 13.0, *) { let appearance = UINavigationBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor = .clear appearance.titleTextAttributes = [.foregroundColor: UIColor.white] // 新增:配置UIBarButtonItem各状态文字属性 appearance.buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white] appearance.buttonAppearance.highlighted.titleTextAttributes = [.foregroundColor: UIColor.white.withAlphaComponent(0.7)] // 直接传入导航栏标准尺寸生成背景图 let navBarWidth = UIScreen.main.bounds.width let navBarHeight: CGFloat = UINavigationController().navigationBar.bounds.height appearance.backgroundImage = UIImage.getGradientImage(withColors: [#colorLiteral(red: 0.9258083701, green: 0.4127946496, blue: 0, alpha: 1),#colorLiteral(red: 0.7787303329, green: 0.01916297711, blue: 0.1483061314, alpha: 1)], size: CGSize(width: navBarWidth, height: navBarHeight)) // 直接给当前导航栏设置样式,优先级更高 navigationController?.navigationBar.standardAppearance = appearance navigationController?.navigationBar.scrollEdgeAppearance = appearance navigationController?.navigationBar.compactAppearance = appearance // 显式指定导航栏tintColor,确保按钮图标/文字颜色正确 navigationController?.navigationBar.tintColor = .white } else { // iOS13以下版本也补充tintColor配置 navigationController?.navigationBar.tintColor = .white }
3. 可选:自定义UIBarButtonItem避免系统样式影响
如果修改样式后仍有问题,直接用自定义View创建UIBarButtonItem,完全脱离系统按钮样式限制:
let titleLabel = UILabel() titleLabel.text = "Top Title" titleLabel.textColor = .white titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .medium) let topTitle = UIBarButtonItem(customView: titleLabel) self.navigationItem.leftBarButtonItem = topTitle
内容的提问来源于stack exchange,提问作者Saeed Rahmatolahi
相关产品推荐
相关产品推荐

