設(shè)計(jì)目標(biāo)
與objective-c的DKNightMode相同,對(duì)于當(dāng)前控件實(shí)現(xiàn)背景色,字體顏色等在不同模式下的顏色設(shè)置和變更,同時(shí)提供模式變更的閉包調(diào)用
實(shí)現(xiàn)原理
基礎(chǔ)設(shè)計(jì)
NSObject的擴(kuò)展
動(dòng)態(tài)屬性notificaitonManager
- 該設(shè)計(jì)主要的目的是實(shí)現(xiàn)隱式的NSNotificationCenter的注冊(cè)和去注冊(cè),通過observer weak持有self,避免循環(huán)引用;利用selectorToBoolMap確保selector的有效性;析構(gòu)時(shí)隱式確保self從notificationCenter中移除
- 通過addNightObserver,實(shí)現(xiàn)NSNotificaitonCenter的注冊(cè)和selector有效性性檢查.
- NightNightThemeChangeNotification是每次theme發(fā)生變化時(shí)的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, ¬ificationManagerKey) as? NotificationManager {
return manager
}
self.notificationManager = NotificationManager(observer: self)
return self.notificationManager
}
set {
objc_setAssociatedObject(self, ¬ificationManagerKey, 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)
}
}
動(dòng)態(tài)屬性key對(duì)應(yīng)的顏色值
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))
}
動(dòng)態(tài)屬性key對(duì)應(yīng)的顏色值保存,在設(shè)置時(shí)注冊(cè)notificationManager及對(duì)應(yīng)的updateTheme函數(shù)的調(diào)用。
updateTheme和_updateCurrentStatus
實(shí)現(xiàn)updateTheme是所有NSObject對(duì)應(yīng)的響應(yīng)通知的入口,而_updateCurrentStatus則是各種不同控件在響應(yīng)時(shí)的獨(dú)立行為,所有需要響應(yīng)的控件都有必要實(shí)現(xiàn)該方法的繼承。例如:
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()
}
}
}
動(dòng)態(tài)閉包Customize
該設(shè)計(jì)主要是提供在模式轉(zhuǎn)換下的閉包調(diào)用,在這個(gè)層面上不知道為何作者并沒有開放成public方法,所以私下里我對(duì)這個(gè)邏輯進(jìn)行重新整理
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)
}
}
}
通過擴(kuò)展屬性customiz,向所有空間提供模式變更下的閉包調(diào)用。
各類型控件的顏色擴(kuò)展
添加關(guān)聯(lián)的屬性字,實(shí)現(xiàn)多模式下顏色值的保存,實(shí)現(xiàn)_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()
}
}
}
模式切換的各資源類型
- 利用模板實(shí)現(xiàn)有關(guān)模式切換的類型
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)
}
}
該設(shè)計(jì)提供更多彈性增加可在模式變更下切換的資源類文章來源:http://www.zghlxwxcb.cn/news/detail-796974.html
GitHub地址
github地址文章來源地址http://www.zghlxwxcb.cn/news/detail-796974.html
到了這里,關(guān)于swift NightNight夜間模式設(shè)計(jì)分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!