How to enable Dark theme for iOS 12 and lower - swift

I have already added support for iOS13 where there are two switches: first one for the automatic, system based theme and the other switch to turn on and off dark theme and am switching it with the given method:
func changeThemeTo(theme: String){
switch theme {
case "dark":
UIApplication.shared.windows.forEach { window in
if #available(iOS 13.0, *) {
window.overrideUserInterfaceStyle = .dark
} else {
// Fallback on earlier versions
}
}
case "light":
UIApplication.shared.windows.forEach { window in
if #available(iOS 13.0, *) {
window.overrideUserInterfaceStyle = .light
} else {
// Fallback on earlier versions
}
}
case "auto":
UIApplication.shared.windows.forEach { window in
if #available(iOS 13.0, *) {
window.overrideUserInterfaceStyle = .unspecified
} else {
// Fallback on earlier versions
}
}
default: break
}
}
And everything is working fine for iOS 13, but now I need to enable this to work for iOS lower than 13. Is there something I can do similar to window.overrideUserInterfaceStyle = .dark or should I completely change the switching logic as did on https://www.onswiftwings.com/posts/dark-mode/

Related

iOS 16 with broken UIDatepicker .inline

Any one notice that app with date picker with style .inline freeze and crash ?
I used below code at my existing app at Appstore
if #available(iOS 14, *) {
datePicker.preferredDatePickerStyle = .inline
}else {
datePicker.preferredDatePickerStyle = .automatic
}
For working .inline with iOS16 I need to force add this condition
if #available(iOS 16, *) {
datePicker.preferredDatePickerStyle = .inline
}else {
datePicker.preferredDatePickerStyle = .inline
}
Having result:

How can you allow for a user changing to dark or light mode with the app open on iOS?

I have updated views in my app to support dark mode by adding
if #available(iOS 12.0, *) {
if self.traitCollection.userInterfaceStyle == .dark {
//Adapt to dark Bg
} else {
//Adapt to light Bg
}
}
Then, to allow for the case where the user backgrounds the app and returns to it after switching mode, I attach an observer in my viewDidLoad
if #available(iOS 12.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
} else {
// Fallback on earlier versions
}
which triggers the function
#available(iOS 12.0, *)
#objc func willEnterForeground() {
if self.traitCollection.userInterfaceStyle == .dark {
print("App moving to foreground - dark")
//Adapt to dark Bg
} else {
print("App moving to foreground - light")
//Adapt to light Bg
}
}
However, self.traitCollection.userInterfaceStyle still gives the old value so a full reload of the view is required to produce the desired update to the interface.
Using UIApplication.didBecomeActiveNotification instead makes no difference.
You don't need all those messy if statements! Just add your colours to your Asset Catalogue and the right one will automatically be selected. This is similar to how you can add x1, x2 and x3 images, and the right one will be selected.
Go to the Asset Catalogue and at the bottom left, click on the plus button, select "New Color Set":
Give the colour a name, and in the property inspector, set "Appearance" to "Any, Dark":
Choose a colour for each appearance:
Finally, use the UIColor(named:) initialiser to initialise the colours and they will automatically change when the device's dark mode settings change:
someView.backgroundColor = UIColor(named: "myColor")
EDIT:
If the colours are only known at runtime, you can use the init(dynamicProvider:) initialiser (iOS 13 only though):
someView.backgroundColor = UIColor {
traits in
if traits.userInterfaceStyle == .dark {
// return color for dark mode
} else {
// return color for light mode
}
}

swift: ios13 status bar setting error occurs in SideMenu library

I introduced SideMenu in CocoaPods, but an error occurs in the ios13 part of the status bar.But I don't know the correct code.
Would you please teach me?
var statusBarFrame: CGRect {
if #available(iOS 13.0, *) {
// How to do for iOS 13??
} else {
return UIApplication.shared.statusBarFrame
}
}
statusBarFrame has been deprecated in iOS 13,
for iOS 13 you can use this
var statusBarFrame: CGRect {
if #available(iOS 13.0, *) {
return UIApplication.shared.keyWindow!.windowScene!.statusBarManager!.statusBarFrame
} else {
return UIApplication.shared.statusBarFrame
}
}

How can I turn the MKMapView for dark mode?

How can I change the map to dark mode from iOS 13?
I have opt-out from UserInterfaceStyle so system-wide colors will not apply to me, so I'll do it manually.
I've seen this video from apple WWDC2019 - Session 236, at 8:19s but that's for snapshots and I didn't get it.
Actually I was trying something like:
private var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.backgroundColor = .black
}
but it doesn't change the theme or appearance or the traitCollection to dark.
Any suggestion?
This is what you need on the viewDidLoad
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .dark
}
Setting overrideUserInterfaceStyle on viewDidLoad method will force that view controller to use the desired mode you specify.
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
MapSnapShot
if you are trying to take a snapshot and confused with output image colour Use
if #available(iOS 13.0, *) {
mapSnapshotOptions.traitCollection = traitCollection
}
Full code for a MKMapSnapshotter
func mapCamera(location : CLLocationCoordinate2D )-> MKMapSnapshotter {
let mapSnapshotOptions = MKMapSnapshotter.Options()
let region = MKCoordinateRegion(center: location, latitudinalMeters: 500, longitudinalMeters: 500)
mapSnapshotOptions.region = region
mapSnapshotOptions.scale = UIScreen.main.scale
mapSnapshotOptions.size = AppConstants.Size.mapDetailView
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.showsPointsOfInterest = true
if #available(iOS 13.0, *) {
mapSnapshotOptions.traitCollection = traitCollection
}
return MKMapSnapshotter(options: mapSnapshotOptions)
}
In case you got here searching for a macOS solution (like me), simply update the appearance property on MKMapView:
if #available(OSX 10.14, *) {
mapView.appearance = NSAppearance(named: .darkAqua) // .aqua for default mode
}

Images and Darkmode not switching

In a couple of my apps, I have an image covering the view in the background. In my asset catalog, my image has an Any, light and dark variation. In iOS 13, when I launch the app, the correct light or dark mode image is displayed according to the mode set. However, when I switch the mode while the app is running, the image does not change. All other properties change (colors etc) for all controls, but not the image.
I have tried the following with a layoutIfNeeded() and/or layoutSubviews() inside the traitCollectiosnDidChange block:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
print("Changed mode")
self.view.layoutIfNeeded()
self.view.layoutSubviews()
}
}
}
and the Change mode is definitely triggered but the layout does not change.
Is there a way to make sure that the image also displays the correct one?
OK. To answer my own question. I was applying .withHorizontallyFlippedOrientation() to my image and setting it in ViewDidLoad. When I changed the trait color mode, this image was not getting change.
The solution was to to reset the image AND the flip property when the differentColorAppearance triggers. Like this
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
image2.image = UIImage(named: "CourseImage")?.withHorizontallyFlippedOrientation()
}
}
}