| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- //
- // ThemeManager.swift
- // ThemeDemo
- //
- // Created by 邓永豪 on 2017/8/23.
- // Copyright © 2017年 dengyonghao. All rights reserved.
- //
- import UIKit
- let kUpdateTheme = "kUpdateTheme"
- let kThemeStyle = "kThemeStyle"
- final class ThemeManager: NSObject {
- var style: ThemeStyle {
- return themeStyle
- }
-
- static var instance = ThemeManager()
-
- private var themeBundleName: String {
- switch themeStyle {
- case .black:
- return "blackTheme"
- case .o2:
- return "o2Theme"
- default:
- return "defaultTheme"
- }
- }
- // 缓存 image 到内存中,提高重复访问的速度
- private let memoryCache = NSCache<NSString, UIImage>()
- private var themeStyle: ThemeStyle = .o2
- private var themeColors: NSDictionary?
-
- private override init() {
- super.init()
- if let style = UserDefaults.standard.object(forKey: kThemeStyle) as? Int {
- themeStyle = ThemeStyle(rawValue: style)!
- } else {
- UserDefaults.standard.set(themeStyle.rawValue, forKey: kThemeStyle)
- UserDefaults.standard.synchronize()
- }
-
- themeColors = getThemeColors()
- // 收到内存警告时,移除所有缓存
- NotificationCenter.default.addObserver(
- self, selector: #selector(clearMemoryCache), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
- }
- deinit {
- NotificationCenter.default.removeObserver(self)
- }
- @objc private func clearMemoryCache() {
- memoryCache.removeAllObjects()
- }
-
- private func getThemeColors() -> NSDictionary? {
-
- let bundleName = themeBundleName
-
- guard let themeBundlePath = Bundle.path(forResource: bundleName, ofType: "bundle", inDirectory: Bundle.main.bundlePath) else {
- return nil
- }
- guard let themeBundle = Bundle(path: themeBundlePath) else {
- return nil
- }
- guard let path = themeBundle.path(forResource: "themeColor", ofType: "txt") else {
- return nil
- }
-
- let url = URL(fileURLWithPath: path)
- let data = try! Data(contentsOf: url)
-
- do {
- return try JSONSerialization.jsonObject(with: data, options: [JSONSerialization.ReadingOptions(rawValue: 0)]) as? NSDictionary
- } catch {
- return nil
- }
- }
-
- public func updateThemeStyle(_ style: ThemeStyle) {
- if themeStyle.rawValue == style.rawValue {
- return
- }
- themeStyle = style
- UserDefaults.standard.set(style.rawValue, forKey: kThemeStyle)
- UserDefaults.standard.synchronize()
- themeColors = getThemeColors()
- memoryCache.removeAllObjects()
- NotificationCenter.default.post(name: NSNotification.Name(rawValue: kUpdateTheme), object: nil)
- }
-
- public func themeColor(_ colorName: String) -> Int {
- guard let hexString = themeColors?.value(forKey: colorName) as? String else {
- assert(true, "Invalid color key")
- return 0
- }
- let colorValue = Int(strtoul(hexString, nil, 16))
- return colorValue
- }
- // MARK: load image
- public func loadImage(_ imageName: String) -> UIImage? {
- return loadImage(imageName, themeStyle)
- }
- public func loadImage(_ imageName: String, _ style: ThemeStyle) -> UIImage? {
- if imageName.isEmpty || imageName.characters.count == 0 {
- return nil
- }
- var nameAndType = imageName.components(separatedBy: ".")
- var name = nameAndType.first!
- let type = nameAndType.count > 1 ? nameAndType[1] : "png"
- if let image = memoryCache.object(forKey: name as NSString) {
- return image
- }
- guard let themeBundlePath = Bundle.path(forResource: themeBundleName, ofType: "bundle", inDirectory: Bundle.main.bundlePath) else {
- return nil
- }
- guard let themeBundle = Bundle(path: themeBundlePath) else {
- return nil
- }
- var isImageUnder3x = false
- var imagePath = themeBundle.path(forResource: "image/" + name, ofType: type)
- let nameLength = name.count
- if imagePath == nil && name.hasSuffix("@2x") && nameLength > 3 {
- let index = name.index(name.endIndex, offsetBy: -3)
- name = name.substring(with: (name.startIndex ..< index))
- }
- if imagePath == nil && !name.hasSuffix("@2x") {
- let name2x = name + "@2x";
- imagePath = themeBundle.path(forResource: "image/" + name2x, ofType: type)
- if imagePath == nil && !name.hasSuffix("3x") {
- let name3x = name + "@3x"
- imagePath = themeBundle.path(forResource: "image/" + name3x, ofType: type)
- isImageUnder3x = true
- }
- }
- var image: UIImage?
- if let imagePath = imagePath {
- image = UIImage(contentsOfFile: imagePath)
- } else if style != .default {
- // 如果当前 bundle 里面不存在这张图片的路径,那就去默认的 bundle 里面找,
- // 为什么要这样做呢,因为部分资源在不同 theme 中是一样的,就不需要导入重复的资源,使应用包的大小变大
- image = loadImage(imageName, .default)
- }
- if #available(iOS 8, *){} else {
- if isImageUnder3x {
- image = image?.scaledImageFrom3x()
- }
- }
- if let image = image {
- memoryCache.setObject(image, forKey: name as NSString)
- }
- return image
- }
- }
- extension UIImage {
- func scaledImageFrom3x() -> UIImage {
- let theRate: CGFloat = 1.0 / 3.0
- let oldSize = self.size
- let scaleWidth = CGFloat(oldSize.width) * theRate
- let scaleHeight = CGFloat(oldSize.height) * theRate
- var scaleRect = CGRect.zero
- scaleRect.size = CGSize(width: scaleWidth, height: scaleHeight)
- UIGraphicsBeginImageContextWithOptions(scaleRect.size, false, UIScreen.main.scale)
- draw(in: scaleRect)
- let newImage = UIGraphicsGetImageFromCurrentImageContext()!
- UIGraphicsEndImageContext()
- return newImage
- }
-
- }
|