Swift 中能否为自定义 UIBarButtonItem 实现颜色变化的动画效果?
导航栏自定义元素颜色无动画的原因与实现方案
核心原因
你的推测方向是正确的:
UIBarButtonItem本身是模型配置类,并非UIView的子类,它的颜色渲染逻辑没有被默认纳入UIView的隐式动画上下文。- 从iOS13开始,导航栏外观被拆分为独立的*
UINavigationBarAppearance配置对象*,全局tintColor的传播链路被大幅收窄:只有导航栏内部托管的系统返回按钮,会正常响应tintColor变化的动画流程;但手动初始化并赋值给navigationItem.rightBarButtonItem的自定义按钮、以及导航栏标题的文本,本身没有绑定到导航栏全局tintColor的动画传播链路,因此直接修改导航栏tintColor时,这两部分元素不会产生颜色渐变效果。
具体实现方式
自定义右侧UIBarButtonItem的颜色动画
- 不要完全依赖导航栏全局
tintColor的自动颜色传播,把自定义按钮的颜色修改操作直接放入动画闭包即可生效:- 如果是通过
customView初始化的右侧按钮,直接持有自定义视图的引用,对视图自身的tintColor做动画:// 初始化时持有自定义按钮视图引用 let rightButton = UIButton(type: .system) rightButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightButton) // 颜色变化动画 UIView.animate(withDuration: 0.5) { rightButton.tintColor = targetColor } - 如果是通过系统方法初始化的文字类/图片类bar按钮,直接在动画闭包里修改按钮的文本属性、图片渲染颜色即可,无需依赖导航栏全局配置:
UIView.animate(withDuration: 0.5) { // 修改文字类按钮的颜色 self.navigationItem.rightBarButtonItem?.setTitleTextAttributes( [.foregroundColor: targetColor], for: .normal ) // 修改图片类按钮的渲染颜色 self.navigationItem.rightBarButtonItem?.tintColor = targetColor }
- 如果是通过
- 注意:非customView方式创建的系统UIBarButtonItem,颜色存储在自身的属性集中,不会自动跟随导航栏的
tintColor做隐式动画,必须手动将颜色修改放入动画上下文才会生效。
导航栏标题的颜色动画
- 导航栏标题的颜色是存储在导航栏的外观配置对象中的,全局
tintColor的变化无法驱动标题属性的动画渐变,需要在动画闭包中手动修改标题的属性配置:UIView.animate(withDuration: 0.5) { let appearance = UINavigationBarAppearance() // 保留原有导航栏背景配置,避免样式丢失 appearance.backgroundColor = self.navigationController?.navigationBar.standardAppearance.backgroundColor // 配置目标标题颜色 appearance.titleTextAttributes = [.foregroundColor: targetColor] // 同步其他导航栏控件的颜色配置,保证动画步调一致 appearance.buttonAppearance.normal.titleTextAttributes = [.foregroundColor: targetColor] self.navigationController?.navigationBar.standardAppearance = appearance self.navigationController?.navigationBar.scrollEdgeAppearance = appearance } - 无需额外调用
layoutIfNeeded,标题颜色属于视图的绘制属性,不是布局属性,layout触发不会驱动颜色的渐变动画。
统一动画步调的技巧
如果需要让系统返回按钮、自定义右侧按钮、导航栏标题的颜色变化完全同步,不需要拆分多个动画,把所有元素的颜色修改操作放到同一个UIView.animate闭包中即可:系统返回按钮会自动响应导航栏全局tintColor的变化,和其他自定义元素的动画保持完全一致的时长、节奏。
内容的提问来源于stack exchange,提问作者Brolivar
相关产品推荐
相关产品推荐

