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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
接着分析 (result (type_ident (component id='Bool' bind=Swift.(file).Bool))) (brace_stmt range=[re.swift:1:59 - line:14:1] (pattern_binding_decl range=[re.swift:2:5 - line:2:33] (pattern_named type='[UInt8]' 'b') Original init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) )) Processed init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) ))) (var_decl range=[re.swift:2:9 - line:2:9] "b" type='[UInt8]' interface type='[UInt8]' access=private readImpl=stored writeImpl=stored readWriteImpl=stored)
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值