换肤

换肤的应用场景?

一般应用在某些APP , 在节假日更换主题, 或者切换白天或者夜间模式时使用.

一般实现方式

  • 实现基本的换肤功能, 直接替换图片,无缓存主题
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var backImageView: UIImageView!


    // 当前代码, 非常垃圾
    // 代码冗余度高


    override func viewDidLoad() {
        super.viewDidLoad()
        guard let theme =  UserDefaults.standard.value(forKey: "theme") else {return}
        let themeStr = theme as! String

        backImageView.image = UIImage(named: themeStr + "_back.png")
        button.setImage(UIImage(named: themeStr + "_icon.png"), for: UIControlState())
    }


    @IBAction func guoqing() {

        backImageView.image = UIImage(named: "guoqing_back.png")
        button.setImage(UIImage(named: "guoqing_icon.png"), for: UIControlState())
//        button.setBackgroundImage(UIImage(named: "guoqing_icon.png"), forState: UIControlState.Normal)


        UserDefaults.standard.setValue("guoqing", forKey: "theme")
        UserDefaults.standard.synchronize()

    }

    @IBAction func chunjie() {
        backImageView.image = UIImage(named: "chunjie_back.png")
        button.setImage(UIImage(named: "chunjie_icon.png"), for: UIControlState())

        UserDefaults.standard.setValue("chunjie", forKey: "theme")
        UserDefaults.standard.synchronize()
    }

    @IBAction func zhongqiu() {
        backImageView.image = UIImage(named: "zhongqiu_back.png")
        button.setImage(UIImage(named: "zhongqiu_icon.png"), for: UIControlState())
        UserDefaults.standard.setValue("zhongqiu", forKey: "theme")
        UserDefaults.standard.synchronize()
    }
}
  • 使用用户偏好缓存当前皮肤主题, 方便下次进来后依然是上次所选主题。但代码冗余, 重用性差
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var backImageView: UIImageView!


    // 当前代码, 非常垃圾
    // 重用性比较低


    override func viewDidLoad() {
        super.viewDidLoad()

        guard let theme = getTheme() else {return}
        setImage(theme)
    }


    @IBAction func guoqing() {

        setImage("guoqing")
        save("guoqing")
    }

    @IBAction func chunjie() {

        setImage("chunjie")
        save("chunjie")
    }

    @IBAction func zhongqiu() {

        setImage("zhongqiu")
        save("zhongqiu")
    }

    func getTheme() -> String? {
        guard let theme =  UserDefaults.standard.value(forKey: "theme") else {return nil}
        let themeStr = theme as! String

        return themeStr

    }

    func save(_ theme: String) -> () {
        UserDefaults.standard.setValue(theme, forKey: "theme")
        UserDefaults.standard.synchronize()
    }


    func setImage(_ theme: String) -> () {

        backImageView.image = UIImage(named: theme + "_back.png")
        button.setImage(UIImage(named: theme + "_icon.png"), for: UIControlState())
    }

}
  • 在控制器中直接抽取对应方法, 简化代码。缺点:代码重用性差, 如果在别的控制器需要获取或者设置当前主题, 有需要将代码拷贝一份。逻辑分明不明确, 控制器不应当关心 具体的如何存储主题, 获取主题

  • 抽取公共的皮肤管理类, 简化控制器逻辑。

    1. 存在问题:需要写主题名称, 一个字符串容易写错。
    2. 解决方案:由工具类提供一个枚举类型, 供外界直接选择

ThemeTool.swift

import Foundation

class ThemeTool: NSObject {

    // 工具类内部存在的问题
    // "theme" : 是一个字符串, 既然是字符串, 就有可能写错
    // 主题提供, 没有明确指示, 外界直接传递一个字符串过来

   class func save(_ theme: String) -> () {
        UserDefaults.standard.setValue(theme, forKey: "theme")
        UserDefaults.standard.synchronize()
    }

   class func getTheme() -> String? {
        guard let theme =  UserDefaults.standard.value(forKey: "theme") else {return nil}
        let themeStr = theme as! String

        return themeStr

    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var backImageView: UIImageView!


    // 当前代码, 非常垃圾
    // 工具类内部存在的问题 
    //


    override func viewDidLoad() {
        super.viewDidLoad()

        guard let theme = ThemeTool.getTheme() else {return}
        setImage(theme)
    }


    @IBAction func guoqing() {

        setImage("guoqing")
        ThemeTool.save("guoqing")

    }

    @IBAction func chunjie() {

        setImage("chunjie")
        ThemeTool.save("chunjie")
    }

    @IBAction func zhongqiu() {

        setImage("zhongqiu")
        ThemeTool.save("zhongqiu")
    }

    func setImage(_ theme: String) -> () {

        backImageView.image = UIImage(named: theme + "_back.png")
        button.setImage(UIImage(named: theme + "_icon.png"), for: UIControlState())
    }

}
  • 优化工具类, 使用全局常亮, 和枚举
    1. 存在问题:外界获取到主题名称主要的目的, 就是要拼接该主题下的图片(背景图片, 按钮图片), 这个不是控制器的事情
    2. 解决方案:由工具类提供当前主题下的背景图片, 和 按钮图片等等

ThemeTool.swift

import Foundation

let kTheme = "theme"
// OC 枚举, 整型
// swift ,枚举, 是任意类型

enum ThemeType: String {
    case Zhongqiu = "zhongqiu_"
    case Guoqing = "guoqing_"
    case Chunjie = "chunjie_"
}

class ThemeTool: NSObject {

    // 工具类内部存在的问题
    // "theme" : 是一个字符串, 既然是字符串, 就有可能写错
    // 主题提供, 没有明确指示, 外界直接传递一个字符串过来

   class func save(_ theme: ThemeType) -> () {
        UserDefaults.standard.setValue(theme.rawValue, forKey: kTheme)
        UserDefaults.standard.synchronize()
    }

   class func getTheme() -> ThemeType? {
        guard let theme =  UserDefaults.standard.value(forKey: kTheme) else {return .none}
        let themeStr = theme as! String

        return ThemeType(rawValue: themeStr)

    }
}

ViewController.swift

...

@IBAction func guoqing() {

        setImage(.Guoqing)
        ThemeTool.save(ThemeType.Guoqing)

    }

@IBAction func chunjie() {

    setImage(.Chunjie)
    ThemeTool.save(ThemeType.Chunjie)
}

@IBAction func zhongqiu() {

    setImage(.Zhongqiu)
    ThemeTool.save(ThemeType.Zhongqiu)
}

...
  • 再次优化工具类, 增加提供当前主题下对应图片的方法
    1. 存在问题:图片素材名称跟主题名称相关, 美工作图命名比较复杂(对我们开发人员没有多大影响)
    2. 解决方案:改成靠文件夹进行区分不同主题
  • 使用文件夹, 对主题图片进行分类。虚拟文件夹, 无法在APP mainBundle中创建物理路径
  • 直接使用bundle文件夹

ThemeTool.swift

import Foundation
import UIKit

let kTheme = "theme"
// OC 枚举, 整型
// swift ,枚举, 是任意类型

enum ThemeType: String {
    case Zhongqiu = "zhongqiu/"
    case Guoqing = "guoqing/"
    case Chunjie = "chunjie/"
}

enum ImageType: String {
    case Back = "back.png"
    case Icon = "icon.png"
}

class ThemeTool: NSObject {

    class func getImage(_ type: ImageType) -> UIImage? {

        // 1. 获取当前主题
        guard let theme = getTheme() else {return nil}

        let themeStr = theme.rawValue

        // 2. 拼接图片名称
        // back, icon
        let imageTypeStr = type.rawValue
        let imageName = "images.bundle/" + themeStr + imageTypeStr
        return UIImage(named: imageName)


    }


    // 工具类内部存在的问题
    // "theme" : 是一个字符串, 既然是字符串, 就有可能写错
    // 主题提供, 没有明确指示, 外界直接传递一个字符串过来

   class func save(_ theme: ThemeType) -> () {
        UserDefaults.standard.setValue(theme.rawValue, forKey: kTheme)
        UserDefaults.standard.synchronize()
    }

   class func getTheme() -> ThemeType? {
        guard let theme =  UserDefaults.standard.value(forKey: kTheme) else {return .none}
        let themeStr = theme as! String

        return ThemeType(rawValue: themeStr)

    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var backImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 获取主题的目的, 就是为了获取当前主题下的背景图片, 或者前景图片
        setImage()
    }


    @IBAction func guoqing() {

        ThemeTool.save(ThemeType.Guoqing)
        setImage()
    }

    @IBAction func chunjie() {

        ThemeTool.save(ThemeType.Chunjie)
        setImage()

    }

    @IBAction func zhongqiu() {

        ThemeTool.save(ThemeType.Zhongqiu)
        setImage()

    }




    func setImage() -> () {

        backImageView.image = ThemeTool.getImage(ImageType.Back)
        button.setImage(ThemeTool.getImage(ImageType.Icon), for: UIControlState())
    }


}
  • 实现主题颜色

ThemeTool.swift

import Foundation
import UIKit

let kTheme = "theme"
// OC 枚举, 整型
// swift ,枚举, 是任意类型

enum ThemeType: String {
    case Zhongqiu = "zhongqiu/"
    case Guoqing = "guoqing/"
    case Chunjie = "chunjie/"
}

enum ImageType: String {
    case Back = "back.png"
    case Icon = "icon.png"
}


enum ColorType: String {
    case LableForeColor = "labelFC"
    case ButtonColor = "buttonColor"
}

class ThemeTool: NSObject {


    class func getColor(_ type: ColorType) -> UIColor? {

        // 1. 获取当前主题
        guard let theme = getTheme() else {return nil}
        let themeStr = theme.rawValue





        // 颜色的存储方案
        // r255 g 222,b 123
        // 2. 取出不同主题对应路径下面的颜色配置文件
         let fullPath = Bundle.main.path(forResource: "ColorConfig.plist", ofType: nil, inDirectory: "images.bundle/" + themeStr)

        // 3. 加载里面所有的颜色(字典 key, value)
        let dic = NSDictionary(contentsOfFile: fullPath!) ?? NSDictionary()


        // 4. 根据颜色类型, 取出字典里面对应的值
        // 21,123,233
        guard let colorStr = dic[type.rawValue]  else {return nil}

        let colorStr2 = colorStr as! NSString

        // 5. 分解字符串, 创建颜色对象,
        let colorArray = colorStr2.components(separatedBy: ",")

        if colorArray.count < 3 {
            return nil
        }


        let red = CGFloat(Int(colorArray[0])!)
        let green = CGFloat(Int(colorArray[1])!)
        let blue = CGFloat(Int(colorArray[2])!)



       let color = UIColor(red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha: 1)



        return color

    }


    class func getImage(_ type: ImageType) -> UIImage? {

        // 1. 获取当前主题
        guard let theme = getTheme() else {return nil}

        let themeStr = theme.rawValue

        // 2. 拼接图片名称
        // back, icon
        let imageTypeStr = type.rawValue
        let imageName = "images.bundle/" + themeStr + imageTypeStr
        return UIImage(named: imageName)

    }


    // 工具类内部存在的问题
    // "theme" : 是一个字符串, 既然是字符串, 就有可能写错
    // 主题提供, 没有明确指示, 外界直接传递一个字符串过来

   class func save(_ theme: ThemeType) -> () {
        UserDefaults.standard.setValue(theme.rawValue, forKey: kTheme)
        UserDefaults.standard.synchronize()
    }

   class fileprivate func getTheme() -> ThemeType? {
        guard let theme =  UserDefaults.standard.value(forKey: kTheme) else {return .none}
        let themeStr = theme as! String

        return ThemeType(rawValue: themeStr)

    }
}

ViewController.swift

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var backImageView: UIImageView!


    // 当前代码, 非常垃圾
    // 工具类内部存在的问题 
    //


    override func viewDidLoad() {
        super.viewDidLoad()

        // 获取主题的目的, 就是为了获取当前主题下的背景图片, 或者前景图片
        setImage()
        setLabelColor()
    }


    @IBAction func guoqing() {

        ThemeTool.save(ThemeType.Guoqing)
        setImage()
        setLabelColor()
    }

    @IBAction func chunjie() {

        ThemeTool.save(ThemeType.Chunjie)
        setImage()
        setLabelColor()
    }

    @IBAction func zhongqiu() {

        ThemeTool.save(ThemeType.Zhongqiu)
        setImage()
        setLabelColor()
    }




    func setImage() -> () {
        // 获取当前主题下, 不同类型的图片(背景, 或者前景)
        backImageView.image = ThemeTool.getImage(ImageType.Back)
        button.setImage(ThemeTool.getImage(ImageType.Icon), for: UIControlState())
    }


    func setLabelColor() -> () {
        // 获取当前主题下的, 不同类型颜色
        label.textColor = ThemeTool.getColor(ColorType.LableForeColor)
        button.backgroundColor = ThemeTool.getColor(ColorType.ButtonColor)
    }

}

results matching ""

    No results matching ""