Here's the issue:
I have an extension that I've written to allow simple customization of the Tab Bar in a standard UIKit app.
The issue is that it works fine -once.
Subsequent attempts to change the appearance are ignored.
I'd be grateful for any assistance in telling me what I am doing wrong.
Below is the extension. If I call setColorsTo(normal:, selected:, disabled: background:)
, it works fine, once; but calling it again, does nothing.
Any ideas?
/* ###################################################################################################################################### */
// MARK: - UITabBarController Extension -
/* ###################################################################################################################################### */
/**
This allows setting the colors for a tab bar.
*/
public extension UITabBarController {
/* ################################################################## */
/**
This allows us to set specific colors for the normal, selected, and background attributes of the tab bar.
All parameters are optional. If not provided, default values for the current theme are used.
- parameters:
- normal: The color to use for an unselected, enabled tab item.
- selected: The color to use for a selected tab item.
- disabled: The color to use for a disabled tab item.
- focused: The color to use for a focused tab item.
- background: The background color to use for the bar.
*/
func setColorsTo(normal inNormalColor: UIColor? = nil,
selected inSelectedColor: UIColor? = nil,
disabled inDisabledColor: UIColor? = nil,
focused inFocusedColor: UIColor? = nil,
background inBackgroundColor: UIColor? = nil) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
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] = [NSAttributedString.Key.foregroundColor: normalColor]
appearance.stackedLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
appearance.inlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
appearance.compactInlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
}
if let selectedColor = inSelectedColor {
appearance.stackedLayoutAppearance.selected.iconColor = selectedColor
appearance.inlineLayoutAppearance.selected.iconColor = selectedColor
appearance.compactInlineLayoutAppearance.selected.iconColor = selectedColor
let selectedTextAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.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] = [NSAttributedString.Key.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] = [NSAttributedString.Key.foregroundColor: focusedColor]
appearance.stackedLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
appearance.inlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
appearance.compactInlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
}
tabBar.standardAppearance = appearance
if #available(iOS 15.0, *) {
tabBar.scrollEdgeAppearance = appearance
}
}
}
CodePudding user response:
Can't reproduce any issue. Your code works fine for me, if I remove the parts of it that are wrong. For example, here's a reduction of your code that just sets the background color of the tab bar, with the wrong lines of code removed, plus the color of the selected tab bar item icon and text — along with view controller code that exercises it:
extension UITabBarController {
func setColorsTo(selected inSelectedColor: UIColor? = nil,
background inBackgroundColor: UIColor? = nil) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
if let backgroundColor = inBackgroundColor {
//tabBar.backgroundColor = backgroundColor // wrong
//tabBar.barTintColor = backgroundColor // wrong
appearance.backgroundColor = backgroundColor
}
if let selectedColor = inSelectedColor {
appearance.stackedLayoutAppearance.selected.iconColor = selectedColor
appearance.inlineLayoutAppearance.selected.iconColor = selectedColor
appearance.compactInlineLayoutAppearance.selected.iconColor = selectedColor
let selectedTextAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: selectedColor]
appearance.stackedLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes
appearance.inlineLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes
appearance.compactInlineLayoutAppearance.selected.titleTextAttributes = selectedTextAttributes
}
tabBar.standardAppearance = appearance
if #available(iOS 15.0, *) {
tabBar.scrollEdgeAppearance = appearance
}
}
}
func delay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
delay(2) {
self.tabBarController?.setColorsTo(selected: .yellow, background: .red)
delay(2) {
self.tabBarController?.setColorsTo(selected: .purple, background: .green)
}
}
}
}
When I run the app, the tab bar turns red, then green, while the selected tab bar item turns yellow, then purple — proving that it works more than once. Therefore I conclude that the issue, if there is one, is caused by other code that you have not told us about.
CodePudding user response:
OK. I figured it out.
I needed to add a setNeedsLayout() to the tab bar, after setting the appearance:
/* ################################################################## */
/**
This allows us to set specific colors for the normal, selected, disabled, focused, and background attributes of the tab bar.
All parameters are optional. If not provided, default values for the current theme are used.
- parameters:
- normal: The color to use for an unselected, enabled tab item.
- selected: The color to use for a selected tab item.
- disabled: The color to use for a disabled tab item.
- focused: The color to use for a focused tab item.
- background: The background color to use for the bar.
*/
func setColorsTo(normal inNormalColor: UIColor? = nil,
selected inSelectedColor: UIColor? = nil,
disabled inDisabledColor: UIColor? = nil,
focused inFocusedColor: UIColor? = nil,
background inBackgroundColor: UIColor? = nil) {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
if let backgroundColor = inBackgroundColor {
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] = [NSAttributedString.Key.foregroundColor: normalColor]
appearance.stackedLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
appearance.inlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
appearance.compactInlineLayoutAppearance.normal.titleTextAttributes = normalTextAttributes
}
if let selectedColor = inSelectedColor {
appearance.stackedLayoutAppearance.selected.iconColor = selectedColor
appearance.inlineLayoutAppearance.selected.iconColor = selectedColor
appearance.compactInlineLayoutAppearance.selected.iconColor = selectedColor
let selectedTextAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.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] = [NSAttributedString.Key.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] = [NSAttributedString.Key.foregroundColor: focusedColor]
appearance.stackedLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
appearance.inlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
appearance.compactInlineLayoutAppearance.focused.titleTextAttributes = focusedTextAttributes
}
tabBar.standardAppearance = appearance
if #available(iOS 15.0, *) {
tabBar.scrollEdgeAppearance = appearance
}
tabBar.setNeedsLayout()
}