UITabBarController外观自定义方法仅首次调用生效问题
问题原因
方法重复调用失效是三个代码逻辑问题导致的:
- 每次调用都初始化全新的
UITabBarAppearance实例,调用configureWithOpaqueBackground()会把新实例的所有样式重置为系统默认值,直接全量覆盖TabBar原有配置。如果后续调用时只传入部分参数,未传入的样式会直接回退到系统默认,而非保留上一次的设置,看起来就像修改没有生效。 - 部分iOS 14~16版本存在TabBar样式缓存机制:TabBar完成首次渲染后,仅修改
standardAppearance/scrollEdgeAppearance不会立即触发所有TabBarItem的样式重绘,同时旧API属性tintColor的优先级在部分系统版本中高于Appearance配置,会覆盖你设置的选中色。 - 遗漏了紧凑布局下的
compactAppearance、滚动紧凑布局下的compactScrollEdgeAppearance属性赋值,横屏等场景下样式更新不会生效。
修复方案
调整Appearance初始化逻辑(基于当前已有的样式拷贝修改,而非新建空实例),补全缺失的属性赋值和强制布局刷新逻辑即可,修复后的完整代码如下:
/* ###################################################################################################################################### */ // MARK: - UITabBarController Extension - /* ###################################################################################################################################### */ /** 快速设置UITabBar颜色样式的扩展 */ public extension UITabBarController { /* ################################################################## */ /** 设置TabBar不同状态下的颜色 所有参数可选,未传入的参数保留上一次设置的值 - parameters: - normal: 未选中、可用状态下的Tab项颜色 - selected: 选中状态下的Tab项颜色 - disabled: 不可用状态下的Tab项颜色 - focused: 聚焦状态下的Tab项颜色 - background: TabBar背景色 */ func setColorsTo(normal inNormalColor: UIColor? = nil, selected inSelectedColor: UIColor? = nil, disabled inDisabledColor: UIColor? = nil, focused inFocusedColor: UIColor? = nil, background inBackgroundColor: UIColor? = nil) { // 基于当前已有的Appearance拷贝,保留之前的配置,而非新建空实例 let appearance = tabBar.standardAppearance.copy() as! UITabBarAppearance appearance.configureWithOpaqueBackground() // 同步TabBar的半透明属性,匹配不透明背景配置 tabBar.isTranslucent = false if let backgroundColor = inBackgroundColor { tabBar.backgroundColor = backgroundColor tabBar.barTintColor = backgroundColor appearance.backgroundColor = backgroundColor } if let normalColor = inNormalColor { appearance.stackedLayoutAppearance.normal.iconColor = normalColor appearance.inlineLayoutAppearance.normal.iconColor = normalColor appearance.compactInlineLayoutAppearance.normal.iconColor = normalColor let normalTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: normalColor] appearance.stackedLayoutAppearance.normal.titleTextAttributes = normalTextAttributes appearance.inlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes appearance.compactInlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes } if let selectedColor = inSelectedColor { // 同步旧API的tintColor,避免低版本系统覆盖选中色 tabBar.tintColor = selectedColor appearance.stackedLayoutAppearance.selected.iconColor = selectedColor appearance.inlineLayoutAppearance.selected.iconColor = selectedColor appearance.compactInlineLayoutAppearance.selected.iconColor = selectedColor let selectedTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: selectedColor] appearance.stackedLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes appearance.inlineLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes appearance.compactInlineLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes } if let disabledColor = inDisabledColor { appearance.stackedLayoutAppearance.disabled.iconColor = disabledColor appearance.compactInlineLayoutAppearance.disabled.iconColor = disabledColor appearance.inlineLayoutAppearance.disabled.iconColor = disabledColor let disabledTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: disabledColor] appearance.stackedLayoutAppearance.disabled.titleTextAttributes = disabledTextAttributes appearance.inlineLayoutAppearance.disabled.titleTextAttributes = disabledTextAttributes appearance.compactInlineLayoutAppearance.disabled.titleTextAttributes = disabledTextAttributes } if let focusedColor = inFocusedColor { appearance.stackedLayoutAppearance.focused.iconColor = focusedColor appearance.inlineLayoutAppearance.focused.iconColor = focusedColor appearance.compactInlineLayoutAppearance.focused.iconColor = focusedColor let focusedTextAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: focusedColor] appearance.stackedLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes appearance.inlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes appearance.compactInlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes } // 同步所有场景下的Appearance配置 tabBar.standardAppearance = appearance tabBar.compactAppearance = appearance if #available(iOS 15.0, *) { tabBar.scrollEdgeAppearance = appearance tabBar.compactScrollEdgeAppearance = appearance } // 强制触发布局刷新,清除系统缓存的旧样式 tabBar.setNeedsLayout() tabBar.layoutIfNeeded() } }
补充说明
- 修复后支持任意次数调用,未传入的参数会自动保留上一次的设置,不会回退到系统默认
- 兼容iOS 13及以上所有系统版本,覆盖普通布局、紧凑布局、滚动边缘场景的样式
- 如果需要半透明效果,把
appearance.configureWithOpaqueBackground()替换为appearance.configureWithDefaultBackground(),同时把tabBar.isTranslucent = false改为tabBar.isTranslucent = true即可
内容的提问来源于stack exchange,提问作者Chris Marshall
相关产品推荐
相关产品推荐

