swift4 App切换主题的实现方法总结

栏目: Swift · 发布时间: 7年前

内容简介:声明:本篇博客的代码来自 @Finb 开发的先上图

声明:本篇博客的代码来自 @Finb 开发的 V2ex-Swift 里的 V2exColor.swift,感谢大大开源这么好用的app

先上图

swift4 App切换主题的实现方法总结

依赖

本DEMO依赖

  • UIColor_Hex_Swift 将16进制的颜色转成swift认识的颜色,可以增加代码可读性
  • KVOController 对app里键值监听的一个库
  • SnapKit 代码设置布局的工具

使用 pod install 安装好

项目里用到的小logo,可以去 https://material.io/tools/icons/?style=baseline 搜索下载

基本代码

ViewTableViewCell.swift

import UIKit
import SnapKit

class ViewTableViewCell: UITableViewCell {

    var titleLabel: UILabel = {
        var label = UILabel()
        label.font = UIFont.systemFont(ofSize: 16)
        return label
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        let bgView = UIView()
        self.selectedBackgroundView = bgView

        self.addSubview(titleLabel)

        self.titleLabel.snp.makeConstraints { (make) in
            make.centerY.equalTo(self.contentView)
            make.left.equalTo(20)
        }
    }

    func bind(_ title : String) {
        self.titleLabel.text = title
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

ViewController.swift

import UIKit
import SnapKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    let menuButton = UIButton()
    let tableView = UITableView()
    let data = ["Swift", "SnapKit", "UIColor_Hex_Swift", "KVOController"]

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "Demo";

        menuButton.contentMode = .center
        menuButton.setImage(UIImage(named: "baseline_brightness_2_black_24pt"), for: UIControl.State.normal)
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: menuButton)
        menuButton.addTarget(self, action: #selector(ViewController.changeMode), for: .touchUpInside)

        self.view.addSubview(self.tableView)
        self.tableView.register(ViewTableViewCell.self, forCellReuseIdentifier: "cell")
        self.tableView.dataSource = self
        self.tableView.delegate = self

        self.tableView.snp.makeConstraints { (make) in
            make.edges.equalTo(0)
        }
    }

    @objc func changeMode() {
        // TODO
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewTableViewCell
        cell.bind(data[indexPath.row])

        return cell
    }

}

AppDelegate.swift 的启动方法进行修改,加上 UINavigationController

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    self.window?.rootViewController = UINavigationController(rootViewController: ViewController())

    return true
}

这样一个简单的列表App就做好了

下面加上主题颜色

主题类

@Finb 大大将主题封装成了一个类,直接拷贝就可以用的,下面是源码,关于最下面设置KVO的代码,我也看不懂,直接用就好 : )

import UIKit
import KVOController
import UIColor_Hex_Swift

//使用协议 方便以后切换颜色配置文件、或者做主题配色之类乱七八糟产品经理最爱的功能

protocol AppColorProtocol{
    var backgroundColor: UIColor {get}
    var cellSelectionColor: UIColor {get}
    var menuButtonColor: UIColor {get}
    var titleTextColor: UIColor {get}
}

class DefaultColor: NSObject,AppColorProtocol {
    static let sharedInstance = DefaultColor()
    fileprivate override init(){
        super.init()
    }

    var backgroundColor : UIColor{
        get{
            return UIColor.white
        }
    }
    var cellSelectionColor: UIColor {
        get {
            return UIColor("#f0f0f0")
        }
    }
    var menuButtonColor : UIColor{
        get{
            return UIColor.black
        }
    }
    var titleTextColor : UIColor{
        get{
            return UIColor.black
        }
    }
}


/// Dark Colors
class DarkColor: NSObject,AppColorProtocol {
    static let sharedInstance = DarkColor()
    fileprivate override init(){
        super.init()
    }
    var backgroundColor : UIColor{
        get{
            return UIColor.black
        }
    }
    var cellSelectionColor: UIColor {
        get {
            return UIColor("#222")
        }
    }
    var menuButtonColor : UIColor{
        get{
            return UIColor.white
        }
    }
    var titleTextColor : UIColor{
        get{
            return UIColor.white
        }
    }
}


class AppColor :NSObject  {
    fileprivate static let STYLE_KEY = "styleKey"

    static let AppColorStyleDefault = "Default"
    static let AppColorStyleDark = "Dark"

    fileprivate static var _colors:AppColorProtocol?
    static var colors: AppColorProtocol {
        get{
            if let c = AppColor._colors {
                return c
            }
            else{
                if AppColor.sharedInstance.style == AppColor.AppColorStyleDefault{
                    return DefaultColor.sharedInstance
                }
                else{
                    return DarkColor.sharedInstance
                }
            }
        }
        set{
            AppColor._colors = newValue
        }
    }

    @objc dynamic var style:String
    static let sharedInstance = AppColor()
    fileprivate override init(){
        if let style = UserDefaults.standard.string(forKey: AppColor.STYLE_KEY) {
            self.style = style
        }
        else{
            self.style = AppColor.AppColorStyleDefault
        }
        super.init()
    }
    func setStyleAndSave(_ style:String){
        if self.style == style {
            return
        }

        if style == AppColor.AppColorStyleDefault {
            AppColor.colors = DefaultColor.sharedInstance
        }
        else{
            AppColor.colors = DarkColor.sharedInstance
        }

        self.style = style
        UserDefaults.standard.setValue(style, forKey: AppColor.STYLE_KEY)
    }
}

//MARK: - 主题更改时,自动执行
extension NSObject {
    fileprivate struct AssociatedKeys {
        static var themeChanged = "themeChanged"
    }

    /// 当前主题更改时、第一次设置时 自动调用的闭包
    public typealias ThemeChangedClosure = @convention(block) (_ style:String) -> Void

    /// 自动调用的闭包
    /// 设置时,会设置一个KVO监听,当V2Style.style更改时、第一次赋值时 会自动调用这个闭包
    var themeChangedHandler:ThemeChangedClosure? {
        get {
            let closureObject: AnyObject? = objc_getAssociatedObject(self, &AssociatedKeys.themeChanged) 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.themeChanged,dealObject,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            //设置KVO监听
            self.kvoController.observe(AppColor.sharedInstance, keyPath: "style", options: [.initial,.new] , block: {[weak self] (nav, color, change) -> Void in
                self?.themeChangedHandler?(AppColor.sharedInstance.style)
                }
            )
        }
    }
}

项目内使用

使用很简单,在需要更新主题的时候改变组件颜色的地方,实现 AppColor 里的闭包函数 themeChangedHandler 就可以了

ViewController.swift 里的 viewDidLoad() 方法里加上这个闭包的实现

override func viewDidLoad() {
    // ...

    self.themeChangedHandler = {[weak self] (style) -> Void in
        self?.view.backgroundColor = AppColor.colors.backgroundColor
        self?.tableView.backgroundColor = AppColor.colors.backgroundColor
        self?.menuButton.tintColor = AppColor.colors.menuButtonColor
        if AppColor.sharedInstance.style == AppColor.AppColorStyleDefault {
            self?.navigationController?.navigationBar.barStyle = .default
        } else {
            self?.navigationController?.navigationBar.barStyle = .black
        }
    }
}

实现一下点击小图标的事件

@objc func changeMode() {
    if AppColor.sharedInstance.style == AppColor.AppColorStyleDefault {
        AppColor.sharedInstance.setStyleAndSave(AppColor.AppColorStyleDark)
    } else {
        AppColor.sharedInstance.setStyleAndSave(AppColor.AppColorStyleDefault)
    }
}

再次运行项目,点点看看,背景,navigationBar都已经可以换色了,但 TableViewCell 还不行,那就在 ViewTableViewCell.swift 里也加上主题更新的闭包实现

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    // ...

    self.themeChangedHandler = {[weak self] (style) -> Void in
        self?.titleLabel.textColor = AppColor.colors.titleTextColor
        self?.backgroundColor = AppColor.colors.backgroundColor
        bgView.backgroundColor = AppColor.colors.cellSelectionColor
    }
}

再运行就没问题了

其它

我在开发 CNodeJS-Swift 项目的时候用到了 XLPagerTabStrip ,这货的颜色设置都是写在 super.viewDidLoad() 方法上面才能生效,这导致了我在更新主题的时候执行闭包函数没效果

解决方法:直接把源码下载下来,在程序里改的 :joy

另外,给大家再推荐一个主题更新的开源库,小项目还是比较好用的 NightNight

原文链接:


以上所述就是小编给大家介绍的《swift4 App切换主题的实现方法总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mobilizing Web Sites

Mobilizing Web Sites

Layon, Kristofer / 2011-12 / 266.00元

Everyone has been talking about the mobile web in recent years, and more of us are browsing the web on smartphones and similar devices than ever before. But most of what we are viewing has not yet bee......一起来看看 《Mobilizing Web Sites》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具