rma*_*ddy 7 uikit uicolor ios uitraitcollection ios13
假设我的应用程式中有自订颜色:
extension UIColor {
static var myControlBackground: UIColor {
return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
}
}
Run Code Online (Sandbox Code Playgroud)
我在自定义控件(和其他地方)中使用它作为控件的背景:
class MyControl: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
backgroundColor = .myControlBackground
}
// Lots of code irrelevant to the question
}
Run Code Online (Sandbox Code Playgroud)
对于iOS 13,我希望我的自定义控件同时支持亮模式和暗模式。
一种解决方案是覆盖traitCollectionDidChange并查看颜色是否已更改,然后根据需要更新我的背景。我还需要提供浅色和深色。
因此,我更新了自定义颜色:
extension UIColor {
static var myControlBackgroundLight: UIColor {
return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
}
static var myControlBackgroundDark: UIColor {
return UIColor(red: 0.4, green: 0.3, blue: 0.2, alpha: 1)
}
}
Run Code Online (Sandbox Code Playgroud)
然后更新我的控制代码:
extension MyControl {
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if #available(iOS 13.0, *) {
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
backgroundColor = traitCollection.userInterfaceStyle == .dark ?
.myControlBackgroundDark : .myControlBackgroundLight
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎可行,但是很笨拙,我碰巧使用的其他任何地方都myControlBackground需要添加相同的代码。
是否有更好的解决方案来让我的自定义颜色和控件同时支持明暗模式?
rma*_*ddy 21
事实证明,使用新的UIColor init(dynamicProvider:)初始化程序确实很容易。
将自定义颜色更新为:
extension UIColor {
static var myControlBackground: UIColor {
if #available(iOS 13.0, *) {
return UIColor { (traits) -> UIColor in
// Return one of two colors depending on light or dark mode
return traits.userInterfaceStyle == .dark ?
UIColor(red: 0.5, green: 0.4, blue: 0.3, alpha: 1) :
UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
}
} else {
// Same old color used for iOS 12 and earlier
return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)
}
}
}
Run Code Online (Sandbox Code Playgroud)
而已。无需定义两个单独的静态变量。控件类不需要对原始代码进行任何更改。无需覆盖traitCollectionDidChange或其他任何内容。
这样做的好处是,您可以在“设置”应用中更改模式后立即在应用切换器中看到颜色更改。当然,当您返回应用程序时,颜色会自动更新。
关于支持明暗模式的相关说明-尽可能使用UIColor提供的多种颜色。请参阅“ UI元素”和“ 标准颜色 ”中可用的动态颜色。当您需要自己的应用特定颜色来支持亮和暗模式时,请以此答案中的代码为例。
在Objective-C中,您可以使用以下方法定义自己的动态颜色:
UIColor + MyApp.h:
@interface UIColor (MyApp)
@property (class, nonatomic, readonly) UIColor *myControlBackgroundColor;
@end
Run Code Online (Sandbox Code Playgroud)
UIColor + MyApp.m:
+ (UIColor *)myControlBackgroundColor {
if (@available(iOS 13.0, *)) {
return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traits) {
return traits.userInterfaceStyle == UIUserInterfaceStyleDark ?
[self colorWithRed:0.5 green:0.4 blue:0.2 alpha:1.0] :
[self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];
}];
} else {
return [self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];
}
}
Run Code Online (Sandbox Code Playgroud)
Mo *_*ani 13
iOS 13 的另一个解决方案是使用 Xcode 的资产编辑器在资产目录中定义自定义颜色。
如文档中所述,当您需要特定颜色时,请将其创建为颜色资产。在您的资产中,为浅色和深色外观指定不同的颜色值。您还可以指定颜色的高对比度版本。
请注意,任何外观变体是在不支持暗模式的旧系统上显示的颜色。
要从资产目录加载颜色值,您可以按名称加载颜色:
// iOS
let aColor = UIColor(named: "customControlColor")
// macOS
let aColor = NSColor(named: NSColor.Name("customControlColor"))
Run Code Online (Sandbox Code Playgroud)
现在,无论何时用户在暗模式和亮模式之间切换,指定的颜色都会通过应用程序动态改变。
在这里,我得到了这个帮助方法来创建动态颜色:
extension UIColor {
static func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
guard #available(iOS 13.0, *) else { return light }
return UIColor { $0.userInterfaceStyle == .dark ? dark : light }
}
}
Run Code Online (Sandbox Code Playgroud)
对于问题中的解决方案,应使用辅助方法如下:
extension UIColor {
static let myControlBackground: UIColor = dynamicColor(light: UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1), dark: UIColor(red: 0.4, green: 0.3, blue: 0.2, alpha: 1))
}
Run Code Online (Sandbox Code Playgroud)
无需覆盖traitCollectionDidChange,只需设置backgroundColor一次即可完成。
如果您想以编程方式创建动态颜色:
可重复使用的扩展:
extension UIColor {
public class func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
if #available(iOS 13.0, *) {
return UIColor {
switch $0.userInterfaceStyle {
case .dark:
return dark
default:
return light
}
}
} else {
return light
}
}
}
Run Code Online (Sandbox Code Playgroud)
应用颜色:
struct MyColors {
///> This is what you are getting from designers,
/// in case they are not providing consistent color naming.
/// Can be also just strings with HEX-codes.
static let xF9EFB1 = #colorLiteral(red: 0.9764705882352941, green: 0.9372549019607843, blue: 0.6941176470588235, alpha: 1)
static let x6A6A6A = #colorLiteral(red: 0.4156862745098039, green: 0.4156862745098039, blue: 0.4156862745098039, alpha: 1)
static let xFEFEFE = #colorLiteral(red: 0.9960784313725490, green: 0.9960784313725490, blue: 0.9960784313725490, alpha: 1)
static let x202020 = #colorLiteral(red: 0.1254901960784314, green: 0.1254901960784314, blue: 0.1254901960784314, alpha: 1)
///<
static var myLabelForeground: UIColor {
return UIColor.dynamicColor(light: MyColors.x6A6A6A, dark: MyColors.xF9EFB1)
}
static var myViewBackground: UIColor {
return UIColor.dynamicColor(light: MyColors.xFEFEFE, dark: MyColors.x202020)
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
class SampleView: View {
private lazy var label = Label(text: "Hello!")
override func setupUI() {
label.textColor = MyColors.myLabelForeground
label.font = UIFont.systemFont(ofSize: 24, weight: .semibold)
backgroundColor = MyColors.myViewBackground
addSubview(label)
LayoutConstraint.centerXY(label).activate()
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
更新:NSColor扩展:
import AppKit
extension NSColor {
public class func dynamicColor(light: NSColor, dark: NSColor) -> NSColor {
if #available(OSX 10.15, *) {
return NSColor(name: nil) {
switch $0.name {
case .darkAqua, .vibrantDark, .accessibilityHighContrastDarkAqua, .accessibilityHighContrastVibrantDark:
return dark
default:
return light
}
}
} else {
return light
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2920 次 |
| 最近记录: |