我在找什么
我正在尝试重新加载我的 View Controller 中的所有 View ,以在主题之间切换(类似于 Twitter
或 Apple Maps
所做的)。
我如何设置不同的主题
我有这样的主题 View 设置:
@IBDesignable
extension UIView {
@IBInspectable
var lightBackgroundColor: UIColor? {
set {
switch GEUserSettings.theme {
case .light: backgroundColor = newValue
case .dark: break
}
}
get {
return self.lightBackgroundColor
}
}
@IBInspectable
var darkBackgroundColor: UIColor? {
set {
switch GEUserSettings.theme {
case .light: break
case .dark: backgroundColor = newValue
}
}
get {
return self.darkBackgroundColor
}
}
}
这允许我在我的 Main.storyboard
中设置 light
和 dark
主题背景颜色,具体取决于当前主题。我的背景模糊效果被排除在外,因为我找不到在代码中更新 style
的方法,所以它是在 viewDidLoad
中创建的。
通过摇动设备触发主题
但是,当我想改变主题时,我不知道该怎么做。我想通过摇动设备来触发它,就像这样:
override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
print("Shaken!")
let oppositeTheme: GEUserSettings.Theme = {
switch GEUserSettings.theme {
case .light: return .dark
case .dark: return .light
}
}()
GEUserSettings.theme = oppositeTheme
// My attempt to update the view controller to
// update the theme, which doesn't do anything.
dismiss(animated: true) {
UIApplication.shared.keyWindow?.rootViewController?.present(self, animated: true, completion: nil)
// Yes, the presenting is working, but the views don't change.
}
}
有哪些可能的解决方案?
如果应用程序退出并重新启动,设置将生效。我可以强制退出该应用程序(不使用 exit(0)
或任何算作崩溃的东西),或者在使用该应用程序时重新加载它。
我尝试关闭然后重新加载 View Controller ,如上面的代码所示。我正在重新加载的那个显示在基本 View Controller 的顶部。
由于我使用的是 Storyboard ,我怎样才能完成这项工作?
编辑 - 添加了我的亮/暗模式的图像以使我的问题更清楚:
最佳答案
如果你打算在你的应用程序中使用主题,Apple 提供了 UIApperance
协议(protocol),它可以帮助你同时更改某种控件的属性,使用它你将拥有统一的外观你的用户界面。使用方法非常简单,改变所有UILabel
的背景颜色是这样的:
UILabel.apperance().backgroundColor = .lightGray
如果您想像在示例代码中那样在一个地方管理所有内容,您可以创建一个包含 UI 特征的结构,检查此结构(我使用了与您相同的名称):
import UIKit
struct GEUserSettings {
enum Theme { case light, dark }
static public var theme: Theme = .light {
didSet {
guard theme != oldValue else { return }
apply()
}
}
static weak var window: UIWindow?
static public func toggleTheme() {
self.theme = theme == .light ? .dark : .light
}
static private func apply() {
setColors()
if let window = window {
window.subviews.forEach({ (view: UIView) in
view.removeFromSuperview()
window.addSubview(view)
})
}
}
static public func setColors() {
switch theme {
case .light:
UILabel.appearance().textColor = .black
UISegmentedControl.appearance().tintColor = .blue
UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).backgroundColor = .clear
UITableViewHeaderFooterView.appearance().backgroundColor = .lightGray
UITableView.appearance().backgroundColor = .white
case .dark:
UILabel.appearance().textColor = .red
UISegmentedControl.appearance().tintColor = .purple
UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).backgroundColor = .clear
UITableViewHeaderFooterView.appearance().backgroundColor = .black
UITableView.appearance().backgroundColor = .darkGray
}
}
}
在 AppDelegate 中,或者尽快,您应该将 UIWindow
引用传递给主题管理器结构。我是在 AppDelegate
didFinishLaunchingWithOptions
中完成的。这是使颜色立即发生变化所必需的。
通过定义此结构,您可以根据需要自定义任何 UI 控件。例如,您可以为 UILabel
定义特定的背景颜色,如果它包含在 UISegmentedControl
中则有不同的背景颜色。
您定义的摇动事件可以像这样在主题之间切换:
override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
GEUserSettings.toggleTheme()
}
如果您摇动设备,屏幕将在这两个屏幕之间切换(我只更改了几个属性):
如果您想尝试示例项目,请访问 Github。
希望能帮到你!
关于ios - 尝试重新加载 View Controller 以更新当前主题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55697172/