Get update for light/dark mode theme change - swift

I have a SwiftUI app, in which I have a SpriteKit scene. However, when changing between light and dark mode, the scene background does not change colour until the app is reopened.
This is not ideal, so I want to register when the light/dark mode appearance is changed. The colour in my assets has an "any" and a "dark" appearance.
Code inside updateUIView() within a UIViewRepresentable struct, which sets up the scene when it is linked with SwiftUI:
scene.backgroundColor = UIColor(named: "Color.Scene")!
uiView.presentScene(scene)
How do I achieve this? I am using iOS 13's system wide dark mode, so I do not want a solution of Notification Center because all I am looking to do is update the background according to the system settings.

You can use #Environment (\.colorScheme) var colorScheme: ColorScheme in your view and make the views body react to it:
struct ContentView: View {
#Environment (\.colorScheme) var colorScheme: ColorScheme
var body: some View {
HStack {
if self.colorScheme == .light {
// draw for light mode
} else {
// draw for dark mode
}
}
}
}

Related

TabBarItem how to change icon color

The default color of inactive TabBarItem icon is gray
How can I change the default color?
XCode 14.2
SwiftUI 4.x.x
You can set the color with appearance settings:
struct ContentView: View {
init() {
UITabBar.appearance().unselectedItemTintColor = UIColor.green
}
var body: some View {
...
}
}
otherwise check another approach shared here: https://stackoverflow.com/a/64727573/4977439
If that is systemImage, set the icon in systemName, then there is a mac app called SF Symbols where you can change the color to the emoji you want!

Custom NavigationView + Status Bar for only one view in SwiftUI

I have an application with a blue background main screen and other white background screens. As I'm using custom colors for the entire app, I decided to use .preferredColorScheme(.light) on the root file (SomethingApp.swift) otherwise it would be a complete mess on dark mode.
#main
struct SomethingApp: App {
var body: some Scene {
WindowGroup {
HomeView()
.preferredColorScheme(.light)
}
}
}
But the result for this main screen is particularly ugly!
I get a black status bar on a blue background and the white navigation title is almost invisible on scroll (white navigation background + bottom border).
So, I've looked for a better solution:
1 - Using .preferredColorScheme(.dark) just for this main screen. The result should be a white status bar and a dark NavigationView on scroll. But no matter where I put this modifier, nothing happens!
2 - Customizing the NavigationView inside an init(). It would be awesome to only have the blur effect on scroll or maybe a very light white background so the title could still be visible. But I've only managed to make the background disappears on scroll (see below).
init() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
UINavigationBar.appearance().standardAppearance = navBarAppearance
// UINavigationBar.appearance().compactAppearance = navBarAppearance
// UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
}
Do you have any other ideas? Thanks.
EDIT
I have just noticed that this init() is applied to all the views which is not what I wanted lol.
Also, I have just discovered to perform the "1 -" by using .colorScheme(.dark) on the NavigationView but unfortunately it doesn't changed the status bar color. But it's a progress!

SwiftUI not detecting dark mode from setting

In SwiftUI on my device, I set the appearance to dark mode. However, my application doesn't change the background colour based on that appearance. For the color asset, I have set the values for both the light and dark appearance, like so
In my code this is how I set the background color and static variable,
extension Color {
static let backgroundColor = Color("Background")
}
..... // In my View
ZStack {
Color.backgroundColor
.ignoresSafeArea()
......
}
Also when I debug and check
#Environment (\.colorScheme) var colorScheme:ColorScheme
it returns that my device is indeed on dark mode. Any idea what is going on and why I'm unable to activate dark mode automatically from the user's device preferences.
Turns out when you use
.preferredColorScheme(.light | .dark)
It applies that preference to the entire view rather than the element the property is being used on.
This code works fine on simulator and device:
struct ColorSchemeView: View {
var body: some View {
Color.backgroundColor
.ignoresSafeArea()
}
}
fileprivate extension Color {
static let backgroundColor = Color("DarkLight")
}
I suspect you have some other issue in the code that will need a true Minimal Reproducible Example (MRE) to debug.

SwiftUI Color doesn't update on main page

All my text in my app use the color Color.textColor which changes due to a UserDefault setting:
extension Color {
public static var textColor: Color {
let color = UserDefaults.standard.bool(forKey: "redText") ? Color.red : Color.white
return color
}
}
This is changed via a toggle in my settings section. The problem is, when I toggle this it successfully changes all text colours all my views, apart from the main view.
I've made a gif here to showcase the problem: https://imgur.com/a/LcN7TBi
The bug is there in both simulation and preview.
Edit: When I switch off/on the preview the main page colours actually update to the correct colour.

How to get rid of the white shadow in dark mode in macOS?

I am making a macOS app in Swift and am seeing a weird issue when I switch b/w light and dark modes. The shadow that appears around the image on the light mode is great but the one I am getting by default on the dark mode doesn't look nice. Does anyone know how to fix this? I am getting the same for all other UI elements like Checkboxes, Radio Buttons, etc.
Not nice
Nice
Note:
This image is added via the Interface Builder in Xcode.
I have the shadow checkbox unchecked as well. See below:
Make sure that the superviews of your view don't define a shadow either or that it has an opaque background.
If your superview doesn't have an opaque background, child views will also have a shadow.
You can either try implementing viewDidChangeEffectiveAppearance() on your NSView or do key-value observations on NSApp.effectiveAppearance. This way you'll be notified about appearance changes between light/dark mode so you can react accordingly.
You can detect whether a view is Dark Mode or not. And you hide shadow when in dark mode.
Add an extension to NSView:
extension NSView {
func isDarkMode() -> Bool {
if #available(OSX 10.14, *) {
return effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
}
return false
}
}
Create a custom view (view, button etc). Override viewDidChangeEffectiveAppearance method in your custom view and update layer.
class CustomView: NSView {
override func viewDidChangeEffectiveAppearance() {
// edit shadow's properties. ex: shadowOpacity.
if isDarkMode() {
// dark mode
} else {
// light mode
}
}
}