尝试重新加载视图控制器以更新当前主题 [英] Trying to reload view controller to update the current theme

查看:76
本文介绍了尝试重新加载视图控制器以更新当前主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图重新加载视图控制器中的所有视图,以在主题之间进行更改(类似于TwitterApple 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中根据当前主题设置lightdark主题背景颜色.我的背景模糊效果被排除在外,因为我找不到在代码中更新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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆