I've just added dark mode to my app.
Asset catalogs support multiple appearances for each asset, on iOS 13 this means the correct asset is used when the system is running in dark or light mode.
These are not my real assets
I'm trying to support dark mode on older iOS versions.
In my attempts to do so, I have added an override to force dark mode which works for my custom colours and theming but not for the images.
Is it possible to access the dark appearance of an image programatically before iOS13?
For iOS12 I have tried using the following:
if #available(iOS 12.0, *) {
let traits = UITraitCollection(userInterfaceStyle: .dark)
let image = UIImage(
named: "Image",
in: bundle,
compatibleWith: traits
)
}
This only returns the normal appearance, and the method naming seems to suggest this only checks that the trait collection I've passed is compatible with the image.
As far as I know, there's no way to do that with just one asset. Below iOS 13 the system will always take the Any appearance. You would need to create two different image sets with different names and choose either one of them.
It is a bit confusing since UIUserInterfaceStyle is available in iOS 12+, but this is likely because macOS got Dark Mode that year.
Related
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
}
I'm displaying PDF files in an iOS / Mac Catalyst app with PDFView. My app has had a dark color theme since long before Apple added Dark Mode to its operating systems, but now that Apple supports this, I'm thinking it should be possible to display the PDFView with a Dark Mode (inverted colors, with white text on a dark background) to match the rest of the app. However, I haven't found a way. Here's what I've tried:
PDFView *pdfView = [[PDFView alloc] init];
pdfView.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; // no effect
pdfView.tintColor = [UIColor blackColor]; // no effect; also tried whiteColor
I found the PDFAppearanceCharacteristics class, and that offers a way to change the PDF background color, but I'd need to change the text and any shape objects, too. (I'm not worried about photos in PDFs, because that doesn't typically occur with my app.) I also checked the PDFDocument and PDFPage classes, but they don't seem to offer anything like this.
I was kind of hoping this would just follow the operating system's Dark Mode automatically, but I'm surprised there's not at least some way to override the colors. Is there an option I'm missing?
For my MacOS app, I created a colors Asset catalog.
The Deployment target for my project is 10.11.
When I set colors at the storyboard, I can choose from the colors asset. But when I try to set one of the named colors programmatically, I need to wrap it in
if #available(OSX 10.13, *) {
view.backgroundColor = NSColor(named: "someColor")
} else {
// Fallback on earlier versions
}
ORIGINAL QUESTION:
So the question is why I'm not getting any warnings for choosing those colors via the storyboard?
I guess I need to replace them with a custom color, or my app will crash on OS < 10.13, but I would expect the storyboard not to let me choose those colors because of the deployment target..
EDITED:
So the question is what happens when I'm using those colors via Storyboard?
Would it crash the app? or maybe the storyboard can handle named colors even for OS versions < 10.13 ? Because I tried to use the named colors via the Storyboard, and I installed the app on a Mac with OS 10.12, and the app worked just fine. So I'm wondering what's the reason for that..
P.S
This question is also relevant to iOS, where the min version for named colors is iOS 11
It will not crash your app. With Colors from Assets Catalog you have two options:
Only use it with storyboards.
Using UIColor(named: <#String #>) like you're trying to do in your question.
The only problem is that UIColor(named:) is available in iOS 11.0+ (See documentation)
So if you'd like to use it every time you need to think about fallback to the oldest version and that may be not quite right what you want.
But there is an other solution build in into Xcode in Media library:
You can drag&drop colors from assets catalog and Xcode will create for you reference for this color that will work in iOS 10.0 as well.
The actual line of code hidden in this color is:
colorLiteral(red: 0.9411764706, green: 0.07843137255, blue: 0.07843137255, alpha: 1)
So you can write a script that will generate this color for you.
Some time ago I need similar solution so I did wrote a script that scan my whole project for assets catalogs and inside them find a colors sets and create UIColor extension containing all the colors from assets:
You can find it here: https://github.com/JakubMazur/SwiftColorsGenerator and it's available to use through Marathon (https://github.com/JohnSundell/Marathon)
By using Jakub's method, color will not work for different appearances (light/dark mode).
Creating color like this worked for me.
extension UIColor {
static var testColor: UIColor = {
return UIColor(named: "TestColor", in: Bundle(for: AppDelegate.self), compatibleWith: nil)!
}()
}
Issue Description
In my application I have a navigation bar search button set up as follows:
static navigatorButtons = {
leftButtons: [
{
id: 'back-nav-button',
icon: require('../assets/images/icons/arrow-left.png')
}
]
};
The button works as intended on both iOS and Android, but the button is blue on iOS. I understand that this is the desired behavior and that the color can be overridden by setting navBarButtonColor, but the problem is that it's a multi-colored button - meaning I want then button to simply contain the PNG image's colors, and not the navBarButtonColor.
I've tried setting navBarButtonColor to null, transparent, but nothing seems to work.
So my question is, is there a way to make navigation bar icons take on the color of the PNG provided, as is the case on Android?
Steps to Reproduce / Code Snippets / Screenshots
Simply run any RNN app on iOS with a simple static navigatorButtons = ... using a local multi-colored PNG and you'll see the colors of the icon get overwritten.
Environment
React Native Navigation version: 1.1.473
React Native version: 0.55.3
Platform(s) (iOS, Android, or both?): iOS
Device info (Simulator/Device? OS version? Debug/Release?): Android Emulator on Debug
On iOS, UIBarButtonItem uses images created with source image's alpha channel. To display the actual image (not an alpha channel mask of it) you need to change your image's rendering mode to alwaysOriginal
Although, looking at React Native Image class documentation I can't see renderingMode property
We've managed to find a workaround for this. By setting the disableIconTint button property to true, it disables the icon color override. See the following example:
static navigatorButtons = {
leftButtons: [
{
id: 'back-nav-button',
icon: require('../assets/images/icons/arrow-left.png'),
disableIconTint: true // Add this line to use the PNG's color
}
]
};
In my iOS application we need to change the color of the icons based on the user configuration. It is one of our important business option.
One of my friend advised me for using .svg or font icon. And shared me this link
They are creating web applications while I am developing iOS application. Does iOS support this technique too? If yes, how can I use it?
Edit
I found SVGKit that is used for the iPhone/iPad apps. Is there any binding library for using it on the monotouch?
SVG fonts (paths) are kind of easy to convert into source code. Once you have this it's very simple to render them in different colours, sizes (iphone/ipad) or resolutions (e.g. retina).
That's what I did here. That's for an older version of FontAwesome, but it could be used as is (or updated to the latest) for your application.
you can use FontAwesome+iOS
all the icons available here: link
If you just need to change color of icons, you probably can solve this without svg. Just use tint colors.
Create a template image:
let templateImage = UIImage(named: "bla_bla")?.withRenderingMode(.alwaysTemplate)
Then add it to a button or an image view and set the tintColor:
button.setImage(templateImage, for: .normal)
button.setImage(templateImage, for: .highlighted)
button.tintColor = UIColor.blue
This solution works only for monochromatic icons!
Besides, if you want .svg, you can use WKWebView, it's really fast and will not cause overhead if you have limited amount of icons.