Swift:夜间模式实现

实现方式有四个重点:

1.定义一个协议,协议里规定了实现主题颜色的各种方法。

2.定义一个主题类,包含两个关键属性stylecolors,style表示对模式变化的监听,colors则可以根据style返回对应的颜色类。

3.扩展NSObject,定义一个闭包,可以在style发生变化的时候被调用,同来通知全局主题发生变化。

4.分别定义颜色类:夜间类和白天类。

 

 

定义协议ThemeColorProtocol:

protocol ThemeColorProtocol {var themeBackgroundColor: UIColor { get }var themeNavigationBarColor: UIColor { get }
}

说明:采用协议的类必须要实现协议的方法,也就是各种主题色。

 

定义两个主题类,都采用协议ThemeColorProtocol:

DarkColor(夜间模式)

/// 夜间颜色
class DarkColor: NSObject, ThemeColorProtocol {static let sharedInstance = DarkColor()fileprivate override init() {super.init()}var themeBackgroundColor: UIColor {get {return UIColor.black}}var themeNavigationBarColor: UIColor {return UIColor.red}}

 

DefaultColor(日间模式)

/// 默认颜色
class DefaultColor: NSObject, ThemeColorProtocol {static let sharedInstance = DefaultColor()fileprivate override init() {super.init()}var themeBackgroundColor: UIColor {get {return UIColor.white}}var themeNavigationBarColor: UIColor {get  {return UIColor.white}}
}

 

创建主题颜色类ThemeColor:

class ThemeColor: NSObject {static let DarkThemeString = "Dark"static let DefaultThemeString = "Default"static let sharedInstance = ThemeColor()fileprivate override init() {super.init()}static var colors: ThemeColorProtocol {get {if ThemeColor().style == ThemeColor.DarkThemeString {return DarkColor()}else {return DefaultColor()}}}var style: String {get {//默认情况下放回default模式if let style = UserDefaults.standard.object(forKey: "StyleKey") {return style as! String}else {return ThemeColor.DefaultThemeString}}set {UserDefaults.standard.set(newValue, forKey: "StyleKey")NotificationCenter.default.post(name: NSNotification.Name(rawValue: THEME_CHANGE_NOTIFICAION), object: nil)//style的值发生变化就发出通知。这样我们在设置里改变主题模式时会马上让APP变化。}}
}

说明:这是个单例类(沿用V2的单例模式,其实不用也没事),有两个关键属性colors和style。

  • colors是ThemeColorProtocol类型的,任何采用了ThemeColorProtocol协议的实例都可以赋值给colors属性,所以这里根据style的值就可以返回对应的颜色实例(黑夜类实例或者白天类实例)。所以我们设置背景的时候可以直接通过colors属性调用协议里对应的颜色属性,如:
//不用这么判断
if ThemeColor.sharedInstance.style == ThemeColor.DarkThemeString {
self.view.backgroundColor = ThemeColor.colors.themeBackgroundColor
}//直接写就行了
self.view.backgroundColor = ThemeColor.colors.themeBackgroundColor

 

  • style有两个值DarkThemeString和DefaultThemeString,分别对应黑夜模式和白天模式。get方法会从userDefaults里读取StyleKey关键字的值,如果为nil则返回默认值DefaultThemeString。set方法会把设置的新值存到userDefault,同时发出style值变化的通知(这里style值前后是否相同都会发出通知)

 

通知全局:

我们使用colors的属性有两种情况,一种是我们主动设置颜色时,如代码

self.view.backgroundColor = ThemeColor.colors.themeBackgroundColor

另外一种是style发生变化时,通知全局变化。一般我们可以使用kvo监听style变化,然后在回调里再次执行上面这句代码,但是为了方便,我扩展NSObject定义了一个闭包函数

let THEME_CHANGE_NOTIFICAION = "thmemChangedNotificaion"
//MARK: - 主题更改时,自动执行
extension NSObject {fileprivate struct AssociatedKeys {static var thmemChanged = "thmemChanged"}/// 当前主题更改时、第一次设置时 自动调用的闭包public typealias ThemeChangedClosure = @convention(block) (_ style:String) -> Void/// 自动调用的闭包/// 设置时,会注册一个通知,当ThemeColor的style关键字变化时,会发送这里注册的通知,同时执行selector对应的函数。var thmemChangedHandler:ThemeChangedClosure? {get {let closureObject: AnyObject? = objc_getAssociatedObject(self, &AssociatedKeys.thmemChanged) as AnyObject?guard closureObject != nil else{return nil}let closure = unsafeBitCast(closureObject, to: ThemeChangedClosure.self)return closure}set{guard let value = newValue else{return}let dealObject: AnyObject = unsafeBitCast(value, to: AnyObject.self)objc_setAssociatedObject(self, &AssociatedKeys.thmemChanged,dealObject,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)NotificationCenter.default.addObserver(self, selector: #selector(themeChangeNotification), name:NSNotification.Name(rawValue: THEME_CHANGE_NOTIFICAION) , object: nil)self.themeChangeNotification()//默认执行一次,为了设置初始颜色}}func themeChangeNotification() {if let closure = self.thmemChangedHandler {closure(ThemeColor().style)}}
}

说明:使用runtime把每个调用了闭包的实例注册通知,并在调用闭包的同时就执行一次闭包,用来设置初始颜色。

转载于:https://my.oschina.net/u/2943743/blog/873419


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部