[英]Adding dark mode to iOS app
我正在尝试向我的应用程序添加一个主题(一个黑暗的主题)。 因此,当用户单击活动开关时,它会使整个应用程序进入黑暗模式。 我对黑暗模式进行了硬编码,只是为了看看它会是什么样子; 但是现在我希望能够通过 UISwitch 启用和禁用它,但我不知道该怎么做?
class DarkModeTableViewCell: UITableViewCell {
var DarkisOn = Bool()
let userDefaults = UserDefaults.standard
@IBOutlet var darkModeSwitchOutlet: UISwitch!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
@IBAction func darkModeSwitched(_ sender: Any) {
if darkModeSwitchOutlet.isOn == true {
//enable dark mode
DarkisOn = true
userDefaults.set(true, forKey: "DarkDefault")
userDefaults.set(false, forKey: "LightDefault")
} else {
//enable light mode
DarkisOn = false
userDefaults.set(false, forKey: "DarkDefault")
userDefaults.set(true, forKey: "LightDefault")
}
}
}
class DarkModeViewController: UIViewController {
func set(for viewController: UIViewController) {
viewController.view.backgroundColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0)
viewController.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
viewController.navigationController?.navigationBar.tintColor = UIColor.white
viewController.navigationController?.navigationBar.barStyle = UIBarStyle.black
viewController.tabBarController?.tabBar.barStyle = UIBarStyle.black
}
static let instance = DarkModeViewController()
}
然后我要做的是在每个视图控制器中调用该函数以查看它的外观,但是如果开关打开或关闭,我需要能够访问 bool 值,如果是,则让它执行该功能,否则只是保持不变。 如果您有任何其他问题,请告诉我,我知道其中一些可能没有多大意义。
更新:这个问题(因此,这个答案)是在 iOS 13 发布之前编写的,因此它不使用 iOS 13 特定的 API。
我会使用 Notifications ( NSNotificationCenter
APIs ) 解决这个问题。
这个想法是在启用暗模式和禁用暗模式时实时通知您的视图控制器,因此它们也可以实时适应变化。 您不需要检查开关的状态或类似的东西。
首先创建两个通知(您也可以只使用一个通知并在userInfo
字典中传递所需的主题,但在这种情况下,创建两个通知更容易,因为您需要使用 Swift 进行转换和其他什么)。
NotificationsName+Extensions.swift
:
import Foundation
extension Notification.Name {
static let darkModeEnabled = Notification.Name("com.yourApp.notifications.darkModeEnabled")
static let darkModeDisabled = Notification.Name("com.yourApp.notifications.darkModeDisabled")
}
在所有“主题化”视图控制器上,收听这些通知:
override func viewDidLoad() {
super.viewDidLoad()
// Add Observers
NotificationCenter.default.addObserver(self, selector: #selector(darkModeEnabled(_:)), name: .darkModeEnabled, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(darkModeDisabled(_:)), name: .darkModeDisabled, object: nil)
}
不要忘记在deinit
删除它们,因为向无效对象发送通知会引发异常:
deinit {
NotificationCenter.default.removeObserver(self, name: .darkModeEnabled, object: nil)
NotificationCenter.default.removeObserver(self, name: .darkModeDisabled, object: nil)
}
在您的“主题化”视图控制器中,实现darkModeEnabled(_:)
和darkModeDisabled(_:)
:
@objc private func darkModeEnabled(_ notification: Notification) {
// Write your dark mode code here
}
@objc private func darkModeDisabled(_ notification: Notification) {
// Write your non-dark mode code here
}
最后,切换您的开关将触发任一通知:
@IBAction func darkModeSwitched(_ sender: Any) {
if darkModeSwitchOutlet.isOn == true {
userDefaults.set(true, forKey: "darkModeEnabled")
// Post the notification to let all current view controllers that the app has changed to dark mode, and they should theme themselves to reflect this change.
NotificationCenter.default.post(name: .darkModeEnabled, object: nil)
} else {
userDefaults.set(false, forKey: "darkModeEnabled")
// Post the notification to let all current view controllers that the app has changed to non-dark mode, and they should theme themselves to reflect this change.
NotificationCenter.default.post(name: .darkModeDisabled, object: nil)
}
}
这样,当“主题”发生变化时,您的所有视图控制器都会实时收到通知,并且它们会做出相应的反应。 请注意,您需要采取措施在应用程序启动时显示正确的模式,但我确定您正在这样做,因为您正在使用 UserDefaults 并且可能正在检查它们。 还值得一提的是 NSNotificationCenter 不是线程安全的,尽管这无关紧要,因为无论如何这些 UI 代码都应该进入主线程。
有关更多信息,您可以查看NSNotificationCenter 文档。
注意:此代码建立在 OP 的基础上。 它可以简化(例如,您不需要同时跟踪“亮”和“暗”状态,只需跟踪一个)。
从 iOS 13 苹果推出了深色主题,如果你想在你的 iOS 应用中添加深色主题,你可以在 viewDidLoad() 上应用以下代码行,如:
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .dark
} else {
// Fallback on earlier versions
}
因此,您可以更改主题,例如有 2 个选项浅色或深色主题。 但是,如果您正在编写上述代码,则只有在运行 iOS 13 的设备上才会始终采用深色主题。
overrideUserInterfaceStyle = .light
或者,如果您的设备已经在 iOS 13 上运行,您可以更改主题,例如:
您甚至可以检查当前设置的主题,例如:
if self.traitCollection.userInterfaceStyle == .dark{
print("Dark theme")
}else{
print("Light theme")
}
让我们看看这个例子:
override func viewDidLoad() {
super.viewDidLoad()
if self.traitCollection.userInterfaceStyle == .dark{
self.view.backgroundColor = UIColor.black
}else{
self.view.backgroundColor = UIColor.white
}
}
结果:
这是相同的视频: https : //youtu.be/_k6YHMFCpas
基本上有两种方法可以为您的应用程序设置主题。 方法一:使用苹果的UIAppearance代理。 如果您的应用程序在所有视图和控件中的颜色使用非常一致,那么这非常有效,如果您有一堆异常,则效果不佳。 在这种情况下,我建议使用像SwiftTheme这样的第三方 pod
请注意,这种方法已被 Apple 在全球范围内将“暗模式”引入(几乎)所有平台所取代。 现在要走的路是具有外观变体的“命名颜色”。
要在 iOS 13 及更高版本中支持暗模式,您可以使用 unicolor Closure。
@objc open class DynamicColor : NSObject{
public var light : UIColor
public var dark : UIColor
public init(light : UIColor,dark : UIColor) {
self.light = light
self.dark = dark
}
}
extension DynamicColor{
public func resolve() -> UIColor{
return UIColor.DynamicResolved(color: self)
}
}
extension UIColor{
class func DynamicResolved(color: DynamicColor) -> UIColor{
if #available(iOS 13.0, *) {
let dynamicColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in
if traitCollection.userInterfaceStyle == .dark {
return color.dark
} else {
return color.light
}
}
return dynamicColor
} else {
// Fallback on earlier versions
return color.light
}
}
}
在视图中使用它时
UIView().backgroundColor = DynamicColor(light: .white, dark: .black).resolve()
//OR
UIView().backgroundColor = UIColor.DynamicColor(light: .white, dark: .black)
在 SwiftUI 中,这变得更容易了。 只需在视图中包含环境变量colorScheme
并检查它的暗模式,如下所示:
struct DarkModeView: View {
@Environment(\.colorScheme) var colorScheme: ColorScheme
var body: some View {
Text("Hi")
.foregroundColor(colorScheme == .dark ? .white : .black)
}
}
有一个关于这一切是如何工作的一个伟大的文章在这里
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.