I've got a TabView which hosts 3 tabs (Liabilities, In/Out, and Assets). Each tab has a NavigationView in it. I want to have a different Nav Bar Appearance for each (red themed for Liabilities, white for In/Out, and green-themed for Assets).
I am able to set the background colors of the nav bars without any difficulty, using something like this:
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.toolbarBackground(Color.liabilitiesnav, for: .navigationBar)
This only lets me set the color of the background though, but I need to be able to change the colors of the other elements in the nav bar. The buttons that I add to the toolbar I can control by explicitly setting their colors, so that's no problem. But the nav title and the back button text and icon are only controllable using the global UINavigationBar.appearance() functionality. But I don't want a global appearance, I want to configure the different tabs with different appearances. This is really important because my AccentColor is a dark green and while that green looks nice on the back button and toolbar items on the Assets tab... it is a horrible green on red on the Liabilities tab. That's why I need to be able to control them separately.
I've tried using an .onAppear { } mechanic to try to change the global appearance to match the current tab whenever that tab appears. For example, on the Liabilities tab, I have:
NavigationView {
List {
// stuff
}
.onAppear {
// tried it here...
NavHelper.useRedAppearance()
}
}
.onAppear {
// and tried it here as well
NavHelper.useRedAppearance()
}
However, it seems to get out of sync. It will start off correctly (Liabilities = red and Assets = green) but when I click back and forth between the Liabilities and Assets tabs, the updates seem to get out of sync and sometimes the Liabilities shows up green and sometimes the Assets shows up red. I added some print statements to the onAppear code and I could see that the useRedAppearance() was getting called when I clicked on the Liabilities tab and the useGreenAppearance() was getting called when I clicked on the Assets tab... but the colors wouldn't necessarily update every time... and thus, got out of sync.
Here is a partial paste of NavHelper just in case I'm doing something wrong in there:
class NavHelper {
static func useRedAppearance() {
let textcolor = UIColor.moneyred
let backgroundcolor = UIColor.liabilitiesnav
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = backgroundcolor
appearance.titleTextAttributes = [.foregroundColor: textcolor]
appearance.largeTitleTextAttributes = [.foregroundColor: textcolor]
let buttonAppearance = UIBarButtonItemAppearance()
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: textcolor]
let image = UIImage(systemName: "chevron.backward")!.withTintColor(textcolor, renderingMode: .alwaysOriginal)
appearance.setBackIndicatorImage(image, transitionMaskImage: image)
appearance.buttonAppearance = buttonAppearance
appearance.backButtonAppearance = buttonAppearance
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().compactScrollEdgeAppearance = appearance
}
}
How can I either (a) reliably switch the global appearance back and forth without getting out of sync, or (b) individually configure the views in the different tabs so they just have a fixed color theme?
