swift NightNight夜间模式设计分析

这篇具有很好参考价值的文章主要介绍了swift NightNight夜间模式设计分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

设计目标

与objective-c的DKNightMode相同,对于当前控件实现背景色,字体颜色等在不同模式下的颜色设置和变更,同时提供模式变更的闭包调用

实现原理

基础设计

NSObject的扩展

动态属性notificaitonManager
  • 该设计主要的目的是实现隐式的NSNotificationCenter的注册和去注册,通过observer weak持有self,避免循环引用;利用selectorToBoolMap确保selector的有效性;析构时隐式确保self从notificationCenter中移除
  • 通过addNightObserver,实现NSNotificaitonCenter的注册和selector有效性性检查.
  • NightNightThemeChangeNotification是每次theme发生变化时的notificaiton通知逻辑
private class NotificationManager {
    var selectorToBoolMap: [Selector: Bool] = [:]
    weak var observer: NSObject?

    init(observer: NSObject) {
        self.observer = observer
    }

    deinit {
        if let observer = observer {
            NotificationCenter.default.removeObserver(observer)
        }
    }

}

extension NSObject {
    fileprivate var notificationManager: NotificationManager {
        get {
            if let manager = objc_getAssociatedObject(self, &notificationManagerKey) as? NotificationManager {
                return manager
            }
            self.notificationManager = NotificationManager(observer: self)
            return self.notificationManager
        }
        set {
            objc_setAssociatedObject(self, &notificationManagerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func addNightObserver(_ selector: Selector) {
        if let bool = notificationManager.selectorToBoolMap[selector] {
            if bool {
                return
            }
        } else {
            notificationManager.selectorToBoolMap[selector] = true
        }
        NotificationCenter.default.addObserver(self, selector: selector, name: NSNotification.Name(rawValue: NightNightThemeChangeNotification), object: nil)

    }

}

动态属性key对应的颜色值
    func getMixedColor(_ key: UnsafeRawPointer) -> MixedColor? {
        return objc_getAssociatedObject(self, key) as? MixedColor
    }
    func setMixedColor(_ key: UnsafeRawPointer, value: MixedColor?) {
        objc_setAssociatedObject(self, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        addNightObserver(#selector(_updateTheme))
    }

动态属性key对应的颜色值保存,在设置时注册notificationManager及对应的updateTheme函数的调用。

updateTheme和_updateCurrentStatus

实现updateTheme是所有NSObject对应的响应通知的入口,而_updateCurrentStatus则是各种不同控件在响应时的独立行为,所有需要响应的控件都有必要实现该方法的继承。例如:

public extension UITableView {
    override func _updateCurrentStatus() {
        super._updateCurrentStatus()
        
        if let mixedSeparatorColor = mixedSeparatorColor {
            separatorColor = mixedSeparatorColor.unfold()
        }
        
        if let mixedSectionIndexBackgroundColor = mixedSectionIndexBackgroundColor {
            sectionIndexBackgroundColor = mixedSectionIndexBackgroundColor.unfold()
        }
        
    }
}

public extension UIView {
    override func _updateCurrentStatus() {
        super._updateCurrentStatus()
        
        if let mixedBackgroundColor = mixedBackgroundColor {
            backgroundColor = mixedBackgroundColor.unfold()
        }
        
        if let mixedTintColor = mixedTintColor {
            tintColor = mixedTintColor.unfold()
        }
        
    }
}

动态闭包Customize

该设计主要是提供在模式转换下的闭包调用,在这个层面上不知道为何作者并没有开放成public方法,所以私下里我对这个逻辑进行重新整理

open class Customize: NSObject {
    fileprivate var closures: [(NightNight.Theme) -> ()] = []
    fileprivate weak var correspondingObject: NSObject?

    fileprivate convenience init(obj: NSObject) {
        self.init()
        self.correspondingObject = obj

        NotificationCenter.default.addObserver(self, selector: #selector(_callAllExistingClosures), name: NSNotification.Name(rawValue: NightNightThemeChangeNotification), object: nil)
    }

    @objc func _callAllExistingClosures() {
        closures.forEach {
            $0(NightNight.theme)
        }
    }
}

通过扩展属性customiz,向所有空间提供模式变更下的闭包调用。

各类型控件的颜色扩展

添加关联的属性字,实现多模式下颜色值的保存,实现_updateCurrentState方法

public extension UIView {
    
    var mixedBackgroundColor: MixedColor? {
        get { return getMixedColor(&Keys.backgroundColor) }
        set {
            backgroundColor = newValue?.unfold()
            setMixedColor(&Keys.backgroundColor, value: newValue)
        }
    }
    
    var mixedTintColor: MixedColor? {
        get { return getMixedColor(&Keys.tintColor) }
        set {
            tintColor = newValue?.unfold()
            setMixedColor(&Keys.tintColor, value: newValue)
        }
    }
    

    override func _updateCurrentStatus() {
        super._updateCurrentStatus()
        
        if let mixedBackgroundColor = mixedBackgroundColor {
            backgroundColor = mixedBackgroundColor.unfold()
        }
        
        if let mixedTintColor = mixedTintColor {
            tintColor = mixedTintColor.unfold()
        }
        
    }
}

模式切换的各资源类型

  • 利用模板实现有关模式切换的类型
public class MixedResource<T> {
    public let normalResource: T
    public let nightResource: T
    public init(normal: T, night: T) {
        normalResource = normal
        nightResource = night
    }

    public func unfold() -> T {
        switch NightNight.theme {
        case .normal: return normalResource
        case .night:  return nightResource
        }
    }
}

  • UIColor,UIImage, UIStatusBarStyle,UIBarStyle,UIKeyboardAppearance
public class MixedImage: MixedResource<UIImage> {
    public override init(normal: UIImage, night: UIImage) {
        super.init(normal: normal, night: night)
    }
    public convenience init(normal: String, night: String) {
        self.init(normal: UIImage(named: normal)!, night: UIImage(named: night)!)
    }
}

public class MixedColor: MixedResource<UIColor> {
    public override init(normal: UIColor, night: UIColor) {
        super.init(normal: normal, night: night)
    }
    public init(normal: Int, night: Int) {
        let normalColor = UIColor(rgb: normal)
        let nightColor = UIColor(rgb: night)
        super.init(normal: normalColor, night: nightColor)
    }
}

该设计提供更多弹性增加可在模式变更下切换的资源类

GitHub地址

github地址文章来源地址https://www.toymoban.com/news/detail-796974.html

到了这里,关于swift NightNight夜间模式设计分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • iOS开发Swift-枚举

    枚举:一组相关的值定义了一个共同的类型,使你可以在代码中以类型安全的方式来使用这些值。 原始值:定义枚举时被预先填充的值。 (1)整数为原始值时,隐式赋值递增1。未设置原始值时,默认为0,之后递增1. (2)字符串为原始值,隐式赋值为枚举成员的名称。

    2024年02月11日
    浏览(53)
  • iOS开发Swift-闭包

    将很长的闭包表达式作为最后一个参数传递给函数,不用写出他的参数标签。 嵌套函数可捕获其外部函数所有参数、变量、常量。 当一个闭包作为一个参数传到一个函数中,但闭包在函数返回之后才被执行,则称闭包逃逸。 标注@escaping,表示允许闭包逃逸。  包装传递给函数

    2024年02月11日
    浏览(60)
  • iOS开发Swift-函数

     (1)无参函数 (2)多参函数 (3)无返回值 (4)多重返回值 (5)可选元组返回类型(元组可以是nil) (6)隐式返回的函数 任一可以被写成一行return的函数,return(x) + for。 调用的时候: 方法名(for: 参数) (1)指定参数标签 (2)忽略参数标签 (3)默认参数值 (4)可变参数 一个可变参数可接受0个或多

    2024年02月11日
    浏览(52)
  • iOS开发Swift-控制流

    (1)复合匹配 (2)区间匹配 (3)元组匹配 (4)值绑定匹配 (5)where continue, break, fallthrough, return, throw continue: 停止本次循环,开始下次循环 break: 立即结束整个控制流。可以使用break忽略switch的分支。 fallthrough贯穿: switch中的case加入贯穿,case会穿透到下一个case/ default。

    2024年02月11日
    浏览(52)
  • iOS开发Swift-类型转换

    1.Int或Double转字符串 2.Double转Int(去掉小数点后面的) 3.Int转Double 4.向上转型 5.向下转型

    2024年02月09日
    浏览(46)
  • iOS开发Swift-集合类型

    集合基本类型:数组 Array (有序), 集合 Set (无序不重复), 字典 Dictionary (无序键值对) (1)数组的表示 (2)创建空数组 (3)带值数组 (4)两数组相加创建数组 (5)字面量创造数组 (6)访问数组 (7)添加 (8)修改 (9)删除 (10)遍历 同时需要索引和值时: (1)集合的表示 (2)构造一个集合 (3)字面

    2024年02月11日
    浏览(103)
  • iOS开发Swift-基础部分

    系统可通过赋初始值进行自动推断。 平时可加可不加,同一行中有两句话必须加。 Int           UInt(最好不用) Double 64位 很大/高精度情况下使用 15位小数 Float 32位 对精度要求不高的情况下用 6位小数 十进制数   17 二进制 0b前缀 0b10001 八进制 0o前缀 0o21 十六进制 0x前缀

    2024年02月11日
    浏览(55)
  • iOS开发Swift-基本运算符

    一元 单一操作对象 -a    !b    c! 二元 两个操作对象 2 + 3 三元 三目运算符 a ? b : c 赋值运算符不返回任何值,所以 if x = y { ... } 无效。 +   -   *   / 默认不允许数值运算中溢出。 溢出运算符:   a + b a % b = 余数 a = (b * 倍数) + 余数 所以a % b = a % -b ==     !=         

    2024年02月11日
    浏览(44)
  • iOS开发Swift-1-Xcode创建项目

    1.创建项目 双击Xcode App,选择Create a new Xcode project。  选择创建一个iOS普通的App项目。选择Single View App,点击Next。  填写项目名,组织名称等,点击next。  选择好文件的存储路径,点击create。  2.为前端添加组件 点击Main,选中View,在右下角show the Object library中找到label组件,

    2024年02月10日
    浏览(39)
  • iOS开发Swift-字符串与字符

     前一个\\\"\\\"\\\"前和后一个\\\"\\\"\\\"后无换行  想要实现在代码编写时换行而在实际运行后不换行:  (1)转义字符 \\0 空字符 \\\\ 反斜线 t 水平制表符 n 换行符 r 回车符 \\\" 双引号 \\\' 单引号 要在\\\"\\\"\\\"中使用(\\\"\\\"\\\")时,必须至少写一个转义符。例如 \\\"\\\"\\\" 或 \\\"\\\"\\\" (2)Unicode标量 u{24} 两位十六进制

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包