尝试重新加载视图控制器以更新当前主题 [英] Trying to reload view controller to update the current theme
问题描述
我试图重新加载视图控制器中的所有视图,以在主题之间进行更改(类似于Twitter
或Apple Maps
所做的事情.)
I am trying to reload all the views in my view controller, to change between themes (similar to what Twitter
or Apple Maps
does).
我的主题视图设置如下:
I have themed views setup like so:
@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
中创建的.
This allows me in my Main.storyboard
to set a light
and dark
theme background colour, depending on the current theme. My background blur effect is excluded from this, as I couldn't find a way to update the style
in code, so it is created in viewDidLoad
.
但是,当我想更改主题时,我不确定该怎么做.我想通过摇动设备来触发它,就像这样:
However, when I want to change the theme, I'm not sure how to do it. I want to trigger it from shaking the device, like so:
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)
或任何会导致崩溃的东西),也可以在使用该应用程序时重新加载它.
What are the possible solutions?
The settings take effect if the app is quit and relaunched. I could either force the app to quit (not using exit(0)
or anything that counts as a crash), or reload it whilst using the app.
我尝试关闭然后重新加载视图控制器,如上面的代码所示.我正在重新加载的一个显示在基本视图控制器的顶部.
I tried to dismiss and then reload the view controller, as shown in the code above. The one I am reloading is presented on top of the base view controller.
当我使用情节提要板时,该如何进行这项工作?
How can I make this work, as I am using storyboards?
编辑-添加了我的明/暗模式的图像,使我的问题更清晰:
Edit - Added an image of my light/dark modes to make my question clearer:
推荐答案
我终于使用NotificationCenter
弄清楚了!
GEUserSettings
现在如下所示:
enum GEUserSettings {
enum Theme: String {
case light
case dark
}
/// The current theme for the user.
static var theme: Theme = .dark
#warning("Store theme in UserDefaults")
/// Toggles the theme.
static func toggleTheme() {
switch GEUserSettings.theme {
case .light: theme = .dark
case .dark: theme = .light
}
NotificationCenter.default.post(name: Notification.Name("UpdateThemeNotification"), object: nil)
}
}
GEView
GEView
是我的UIView
自定义子类.这是替代品,而不是我对UIView
的扩展.现在看起来与此类似:
GEView
GEView
is my custom subclass of UIView
. This is a replacement instead of my extension to UIView
. It now looks similar to this:
/// UIView subclass to allow creating corners, shadows, and borders in storyboards.
@IBDesignable
final class GEView: UIView {
// MARK: - Initializers
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Triggers when the theme is changed
NotificationCenter.default.addObserver(self, selector: #selector(updateBackgroundColorNotification), name: Notification.Name("UpdateThemeNotification"), object: nil)
}
@objc
private func updateBackgroundColorNotification() {
updateBackgroundColor()
}
/* ... */
// MARK: - Background
@IBInspectable
var lightBackgroundColor: UIColor? {
didSet {
updateBackgroundColor()
}
}
@IBInspectable
var darkBackgroundColor: UIColor? {
didSet {
updateBackgroundColor()
}
}
/// Updates the background color depending on the theme.
private func updateBackgroundColor() {
switch GEUserSettings.theme {
case .light: backgroundColor = self.lightBackgroundColor
case .dark: backgroundColor = self.darkBackgroundColor
}
}
}
通过motionBegan(_:with:)
更新
Updating through motionBegan(_:with:)
override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
super.motionBegan(motion, with: event)
// Toggles the theme and update the views
GEUserSettings.toggleTheme()
drawerViewModel.updateBlurEffect(drawerView: drawerView)
}
然后将模糊移除并重新创建,如下所示:
And the blur is removed and recreated, as such:
/// Creates the blur effect behind the collection view.
func updateBlurEffect(drawerView: GEView) {
if let blurView = drawerView.subviews[0] as? UIVisualEffectView {
blurView.removeFromSuperview()
}
let blurEffect: UIBlurEffect = {
switch GEUserSettings.theme {
case .light: return UIBlurEffect(style: .light)
case .dark: return UIBlurEffect(style: .dark)
}
}()
let blurView = UIVisualEffectView(effect: blurEffect)
drawerView.addSubview(blurView)
drawerView.sendSubviewToBack(blurView)
GEConstraints.fillView(with: blurView, for: drawerView)
}
这甚至不需要退出应用程序或重新加载视图控制器,它会立即发生!
This doesn't even require quitting the app or reloading the view controller, it happens instantly!
如果愿意,还可以通过更改updateBackgroundColor()
功能来设置颜色变化的动画:
If you wish, you can also animate the color change by changing the updateBackgroundColor()
function:
/// Updates the background color depending on the theme.
private func updateBackgroundColor() {
UIView.animate(withDuration: 0.25) {
switch GEUserSettings.theme {
case .light: self.backgroundColor = self.lightBackgroundColor
case .dark: self.backgroundColor = self.darkBackgroundColor
}
}
}
您还可以为模糊设置动画:
You can also animate the blur as well:
/// Creates the blur effect behind the collection view.
func updateBlurEffect(drawerView: GEView) {
if let blurView = drawerView.subviews[0] as? UIVisualEffectView {
UIView.animate(withDuration: 0.25, animations: {
blurView.alpha = 0
}, completion: { _ in
blurView.removeFromSuperview()
})
}
let blurEffect: UIBlurEffect = {
switch GEUserSettings.theme {
case .light: return UIBlurEffect(style: .light)
case .dark: return UIBlurEffect(style: .dark)
}
}()
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.alpha = 0
drawerView.addSubview(blurView)
drawerView.sendSubviewToBack(blurView)
GEConstraints.fillView(with: blurView, for: drawerView)
UIView.animate(withDuration: 0.25, animations: {
blurView.alpha = 1
})
}
这篇关于尝试重新加载视图控制器以更新当前主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!