Custom Dark Mode iOS Issue - ios

Three enums are set to achieve:
UIUserInterfaceStyleUnspecified -> To listen to iOS setting mode change
UIUserInterfaceStyleLight -> To override LIGHT mode irrespective of iOS setting mode
UIUserInterfaceStyleDark -> To override DARK mode irrespective of iOS setting mode
The problem arises when I set
(Parent_ViewController -> UIUserInterfaceStyleDark) and
(Child_ViewController -> UIUserInterfaceStyleUnspecified)
And then when we switch the settings iOS mode from light to dark or vice versa, there's no change in UI of Child_ViewController and being UIUserInterfaceStyleUnspecified it should've changed but it always has dark theme colors.
Any workarounds or solution is there to address this problem?

Welcome!
ViewControllers will stop propagating the system changes to child controllers when they override the interface style. This also means that a child VC will inherit the interface style of its parent when overrideUserInterfaceStyle is set to .unspecified.
I'm afraid you need some custom implementation if you want to achieve that specific behavior. For instance, by setting the parts you always want to be dark to concrete (undynamic) colors instead of using dynamic system colors.

Related

Swift Automatically Switch App’s Theme At Sunset

There are several apps on the App Store that have the option in the app to automatically switch to dark mode. I’m assuming there is an easy way to implement this, but I can’t seem to find anything about it when looking online. I just want to be able to have the user select an option that will automatically switch to a dark theme if it is after sunset but have the light theme during the day. Anyone know how to do this in swift?
The most reliable – and by far the easiest – way to implement this is to plug into the system's dark mode setting, rather than rolling your own time-based system. This will also allow your users to make their own decision – if they want light mode all the time, or want to temporarily switch to dark mode in the middle of the day, your app will automatically work for them. And they'll thank you for it.
There are various ways you can manage this:
Use Color's built-in definitions, such as .primary and .secondary, and when they don't satisfy, consider using init(UIColor) to convert some of UIKit's larger list of UI Element colors to work with SwiftUI.
If you define your own colors in your Asset catalog and use them via the Color("My Color Name") syntax, you can elect to set a dark mode variant to use (by changing the Appearance setting from None to Any, Dark).
When the iOS system changes from light to dark and back, your color variants will get selected automatically. These might be a slight variation – e.g., a different shade of purple that looks better when working with dark colors – or it could be something that inverts completely (light gray to dark gray, for example).
If you need to make any more drastic changes – like changing line weights in dark mode – your views can find out whether dark mode is enabled by using the colorScheme environment variable:
struct MyView: View {
#Environment(\.colorScheme) private var colorScheme
// ...
}
colorScheme will be either .dark or .light depending on the phone settings.
However, if you are insistent that you want to have control over light and dark mode instead of letting the system take on that responsibility, you can use the same environment value from step 3 and override it. For example:
struct ContentView {
var body: some View {
MyView()
.environment(\.colorScheme, .dark)
}
}
In that example MyView, and its children, will then behave as if dark mode is always on and everything else – auto-selection of colors from the asset catalog, etc. – will work.
So if you wanted to, you could come up with your own time-based approach to determine whether to set the colorScheme environment to .light or .dark.
However, I'd recommend again to let the system handle everything unless you have a very good reason not to.
If you want to make your own, custom dark mode you can use traitCollectionDidChange to detect when iOS goes in and out of dark mode and then perform your customisation. This is only for iOS 13 and above.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection) //always call this first
}

SafeAreas misbehave when presenting a UIViewController

I need to present a UIViewController (ViewControllerTwo) that only supports ".landscape" orientations from another UIViewController (ViewControllerOne) that only supports ".portrait" orientation. If you check the .gif below, you will notice that when the transition occurs it shrinks the content of "ViewControllerOne" and when you dismiss "ViewControllerTwo" the same happens.
The reason why this happens is related to the change of safe areas, which in portrait are different from landscape and vice versa. But if we override supportedInterfaceOrientations of "ViewControllerOne" to just support ".portrait" it should not be informed of the safe area changes if these changes relate to an unsupported orientation right?
Is this a bug/limitation from iOS?
(NO) -> What is the right way to handle this scenario?
(YES) -> What workaround do you recommend to solve this issue in the meantime?
You can check the Example Project here: https://github.com/mantuness/ExampleProject
Check the GIF below:

In iOS 13 - How can we implement more than two color modes / themes?

Looking at the brand new WWDC video Implementing Dark Mode on iOS we see that it can be handled quite easily. We can use the new dynamic system colors and they will have specific values depending on Light or Dark Mode.
Now, how can this new concept be combined with the need to implement more than two themes – in a clean and future-proof way?
I have have researched and applied different theming approaches in the past like the UIAppearance approach (e.g. Ray Wenderlich´s UIAppearance Tutorial) or a protocol-based custom dynamic colors approach.
Is the following code an appropriate position to start by finding out when the system requires a switch from light to dark mode and vice versa? And then by changing app wide colors in any of the possible "old" ways?
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
/// Really have to go from here?
}
}

Xcode: reverting back to default color in iOS

I am trying to find a way to revert back to the system default color programmatically for iOS components using code. The only other way would be to use 2 controls - 1 set to either color and switch them.
Any info is appreciated. Thanks.
I tried below code in order to change the background of a button to its default color and it worked for me
submitBtn.backgroundColor = UIColor.clear

Is there a way to check if "increase contrast" is enabled in the accessibility settings in iOS?

On iOS 7.0.3 turning on increased contrast mode removes the blur effects you'd normally see in the nav bar if you're using a bar tint color with an alpha less than 1.0, which makes the nav bar seem much more transparent than it is with the default settings.
Is there a way to programmatically check to see if this setting is enabled? While UIAccessibility has a ton of other functions like UIAccessibilityIsInvertColorsEnabled(), I can't find anything related to this setting specifically.
As of iOS 8 there is a way to check:
UIKIT_EXTERN BOOL UIAccessibilityDarkerSystemColorsEnabled() NS_AVAILABLE_IOS(8_0);
as of modern iOS:
UIAccessibility.isDarkerSystemColorsEnabled
Apparently there's no public API for checking whether that option is on.
According to the UIKit Function Reference, the only checks you can perform are the following
UIAccessibilityPostNotification
UIAccessibilityIsVoiceOverRunning
UIAccessibilityIsClosedCaptioningEnabled
UIAccessibilityRequestGuidedAccessSession
UIAccessibilityIsGuidedAccessEnabled
UIAccessibilityIsInvertColorsEnabled
UIAccessibilityIsMonoAudioEnabled
UIAccessibilityZoomFocusChanged
UIAccessibilityRegisterGestureConflictWithZoom
UIAccessibilityConvertFrameToScreenCoordinates
UIAccessibilityConvertPathToScreenCoordinates
For iOS 13 and above we can use accessibilityContrast
Documentation
Use this trait to determine whether the user requested a high contrast
between foreground and background content. The user sets the contrast
level in the Accessibility area in Settings.
Apple doc link

Resources