ChameleonSwift 3.3

ChameleonSwift 3.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2020年7月
SPM支持 SPM

travel 维护。



ChameleonSwift

Language: Swift 5 Platform: iOS 8+

Cocoapods compatible License: MIT

这是一个轻量级且完全用 Swift 实现的库,用于切换应用主题/皮肤。Chameleon致力于提供一种简单的方式来启用应用切换主题。

如果您有任何问题,可以通过电子邮件([email protected])或留言与我联系。

要求

  • iOS 8.0+
  • Xcode 7.0 或更高版本

使用说明

简单示例

假设

你可以用任何数据来定义你的主题。让我们假设你的主题数据是ThemeStyle(Day, Night)。ThemeStyle是枚举类型,但是你可以用任何类型来定义你的主题。

1 启用视图切换主题的功能

let label = UILabel()
label.ch.refreshBlock = { (now:Any, pre:Any?) -> Void in
    // your code change theme/skin
    if let now = ChameleonHelper<ThemeStyle>.parse(now) { // get your ThemeStyle from now
        label.text = "\(now)"
        ...
    }
}

或者你可以重写视图的方法:switchTheme(now:pre:)

override func switchTheme(now: Any, pre: Any?) {
    // your code change theme/skin
    if let now = ChameleonHelper<ThemeStyle>.parse(now) {
        ...
    }
}
  • now:传递给switchTheme的数据。你可以使用ChameleonHelper.parse(now)获取你的真实主题数据
  • pre:传递给switchTheme的前一个数据

2 设置你的主题

  • 切换整个应用程序的主题
    ThemeServiceConfig.shared.initTheme(data: ThemeStyle.Day)
  • 注意:如果你没有初始ThemeData,switchTheme(now:pre:)参数中的now或在ch.refreshBlock中可能会为nil

3 切换主题

  • 切换整个应用程序的主题
    UIApplication.ch.refresh(with: ThemeStyle.Night)
  • 切换指定视图的主题(子视图也包括)
    viewInstance.ch.refresh(with: ThemeStyle.Night)
  • 切换指定视图控制器(包括子视图控制器)的主题
    viewControllerInstance.ch.refresh(with: ThemeStyle.Night)

有用的辅助函数

ChameleonHelper中定义了一些有用的函数。

  • 获取当前主题:ChameleonHelper.current
  • 从参数中获取当前主题:ChameleonHelper.parse()
  • 获取当前主题图片:ChameleonHelper.image()
  • 获取当前主题颜色:ChameleonHelper.color()
  • 获取当前主题数据:如果你的图像/颜色不能满足你的需求,使用ChameleonHelper.currentData()

高级用法

  • 1, 自动回调配置为了节省你的时间,ThemeServiceConfig可能是你的最爱。一些属性是为你预先定义的。当给定属性为真时,ChameleonUIProtocol用户会使用它的父数据ch.refreshBlock或switchTheme(now:pre:)

        // config your theme switch
        ThemeServiceConfig.shared.autoSwitch = [.viewDidMoveToWindow, .viewControllerViewWillAppear]

    注意:自动调用很方便,能节省你的时间,但你应该遵循一些规则,否则你可能会遇到麻烦。

    • 无崩溃:请务必记住,你应该保证ChameleonUIProtocol和ch.refreshBlock运行而不崩溃。如果不幸发生了这种情况,你的应用程序会崩溃。
    • 保存你的状态:你应该在没有状态的地方保存你的状态,并且主题切换方法应该的状态感知。由于回调是自动的,如果你或你的外观与状态相关,可能无法正常工作。例如,你有一个按钮,其主题与状态相关。在白天,它的背景色是黑色,在夜间是白色,如果选中,则是红色;如果你从未保存你的选择状态或主题切换忽略了选择状态,自动回调将无法正常工作。
  • 2, 调用顺序

    • 父子(视图/子视图,视图控制器/子视图控制器)之间的顺序:子视图会先调用父视图;
    • ChameleonUIProtocol和ch.refreshBlock:如果两者都定义了,则ChameleonUIProtocol会先于ch.refreshBlock执行;
    • 视图,视图控制器:如果您的应用切换主题,视图主题切换相关方法会在视图控制器之前运行。如果您在视图和视图控制器中同时更改一个视图主题,视图控制器中的更改将会生效。

    注意:

    • 视图和视图控制器分开工作。如果在视图控制器中调用ch.refresh,其视图主题切换方法将不会运行。
  • 4、您可能发现在视图控制器超出应用rootViewController树时,切换主题方法没有调用。在这种情况下,通常需要调用ch.register()。

    viewControllerInstance.ch.register()
    

    在大多数情况下,您不需要调用此方法,但是您随时可以调用它。

Swift 版本

default support is Swift 4. If you use it in prevous version of Swift. 2.x for Swift3.

迁移

版本 2.2 是破坏性变更。应该在服务器上应用这些变更。

  • 1、func ch_switchTheme(_ now: Any, pre: Any?) 已不可用
    • a、重命名为 switchTheme(now: Any, pre: Any?)
  • 2、ThemeSwitchHelper 到 ChameleonHelper
    • a、func currentTheme() 到属性 current
  • 3、ch_* 函数/属性不可用,请使用 ch.* 替代

安装

CocoaPods

CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令安装它:

$ gem install cocoapods

要使用 CocoaPods 将 ChameleonSwift 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它。

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'ChameleonSwift'

然后,运行以下命令:

$ pod install

安装任何内容后,您应该打开 {Project}.xcworkspace 而不是 {Project}.xcodeproj

ChameleonSwift 介绍

ChameleonSwift 提供了一种机制,你可以很方便地让你的 App 具有多种皮肤和主题。ChameleonSwift 是一个纯 Swift 实现的扩展。由于主题/皮肤切换的复杂性,考虑到易于使用和可扩展性,本库并没有采用其他大多数库采用的方式(为不同的 view 添加不同的属性以达到主题切换),而是采用的是扩展 UIView、UIViewController 的方式,你可以高度定制你想要的皮肤。

与其他主题或皮肤库的优点:

  • 简单。其他库在使用时,不同的 View 需要去添加不同的属性,类型繁多,使用起来不太方便。
  • 易于扩展。本库并没有为不同主题/皮肤下的表现设置单独的属性,而是采用闭包的方式来实现,具有更大的灵活性和自主性。
  • 高度解耦:本扩展只需要简单的配置,你可以专注于业务逻辑,而不需要担心皮肤/主题支持,这样可以让你的代码变得更加简洁。

简单使用:

第一步: 添加对多套皮肤/主题的支持到 view 和 view controller

假设

假设你使用默认的 ThemeStyle(枚举类型,由 Day 和 Night 组成),下面代码中使用了 ThemeStyle 作为你使用的主题类型。当然,在实际使用中,你完全可以自己定义主题类型,可以是枚举,数字,类,可以是任何类型。

有两种方式:你可以通过闭包,也可以通过复写父类的方法来实现。闭包实现方式如下:

let label = UILabel()
label.ch.refreshBlock = { (now:Any, pre:Any?) -> Void in
    // 你修改主题的代码
    if let now = ChameleonHelper<你定义的主题类型>.parse(now) { // 获取 真正的主题
        label.text = "\(now)"
        ...
    }
}
  • 注意:可以通过 ChameleonHelper<你定义的主题类型>.current 获取当前的主题(在接下来的步骤二中会传入此参数)。
override func switchTheme(now: Any, pre: Any?) {
    // your code change theme/skin
    if let now = ChameleonHelper<ThemeStyle>.parse(now) {
        ...
    }
}

参数说明:
* now: 你切换主题是传递进来的参数,比如是白天,还是黑夜等待你可以用 ChameleonHelper<你定义的主题类型>.parse(now),获取当前的主题
* pre: 上次你主题切换使用的参数
好了,通过上面的步骤你已经使得你的view可以支持多种主题了


### 第二步: 设置的主题数据
* 设置整个app
``` swift
    ThemeServiceConfig.shared.initTheme(data: ThemeStyle.Day)
  • 设置单个 view 和其子 view
    viewInstance.ch.refresh(with: ThemeStyle.Night)
  • 设置单个 view controller 和其子 view controller
    viewControllerInstance.ch.refresh(with: ThemeStyle.Night)

第三步: 切换主题,皮肤

你只需要调用一个方法就可以实现。

    UIApplication.ch.refresh(with: ThemeStyle.Night)

当然,你也可以选择行地修改你想要改变 view/view controller 主题的 view 或切换调用。

    viewInstance.ch.refresh(with: ThemeStyle.Night)

view controller 调用

    viewControllerInstance.ch.refresh(with: ThemeStyle.Night)

Swift 版本问题

默认支持 Swift 4 版本,如果需要在 Swift 2 版本使用,请使用 2.x 版本。

有用的帮助函数

ChameleonHelper定义了一些有用的函数

  • 获取当前的主题: ChameleonHelper<你定义的主题类型>.current
  • 解析参数获取当前主题: ChameleonHelper<你定义的主题类型>.parse()
  • 当前主题的图片: ChameleonHelper<你定义的主题类型>.image()
  • 当前主题的颜色: ChameleonHelper<你定义的主题类型>.color()
  • 当前主题的配置(如果图片、颜色不满足你的需求,你可以使用这个): ChameleonHelper<你定义的主题类型>.currentData()

高级使用:

自动调用

在简单使用中,介绍了如何让你的 App 支持主题切换和如何进行切换。但是,你会发现还是很不方便,你需要不断手动调用,主题修改的方法。为了让你从这种无休止的烦恼中解放出来,我们为你提供了主题切换的自动调用配置 ThemeServiceConfig。提供的配置可以满足你绝大多数的需求。

  • viewAutoSwitchThemeAfterAwakeFromNib:在视图从 nib 文件唤醒时自动调用
  • viewAutoSwitchThemeAfterMovedToWindow:在视图被添加到窗口上的时候自动调用(为什么是这个方法而不是 didMoveToWindow?请查阅 apple 的官方文档,关于didMoveToWindow的说明)
  • viewControllerAutoSwitchThemeAfterAwakeFromNib:在视图控制器从 nib 文件唤醒时自动调用
  • viewControllerAutoSwitchThemeWhenViewWillAppear:在视图控制器即将显示之前自动调用

是不是,很方便,简单?

注意

不过任何好用的事物其实都是有代价的,自动调用使得主题切换调用更为隐蔽,诊断响应的问题也不容易。为了更好地使用自动调用,以下是一些建议

  • 确保不抛出异常:ch.refreshBlock 或 ChameleonUIProtocol,不要抛出异常,否则会崩溃
  • 非主题相关的状态保存在视图或者视图控制器中:例如,一个视图具有选中属性,在选中/未选中的不同状态时具有不同的外观,你需要在某个地方存储这个状态,否则外观会被主题切换破坏。例如,主题切换可能将背景色设置为白色或黑色,你的 App 在某个地方可能人为地将其设置为红色,而你恰好配置了自动调用,那么你可能会惊讶地发现视图的颜色不是你想要的红色,你需要考虑到这一点。一种更便捷的方法是记录你设置的红色状态,在主题切换时,发现为红色则不修改背景色。

常见问题:

  • 1,闭包 ch.refreshBlock 和 ChameleonUIProtocol 同时存在,会出现什么问题? 闭包和 ChameleonUIProtocol 都会被调用,只不过闭包会在 ChameleonUIProtocol 调用的后面调用

  • 2,视图控制器主题切换闭包,函数未调用。如果一个修改主题的方法在一个视图控制器中编写,而在使用时只是将控制器视图添加到某个视图上,而视图控制器本身没有附加到任何视图控制器下,可能会出现该视图控制器的某些方法没有自动调用,或者在主题切换时也没有自动调用?如何处理实际上出现这种情况是正常的,这涉及到本库切换的设计原理(后面提到)。您需要手动调用主题切换方法,并使用 viewControllerInstance.ch.register()进行注册。这样就可以实现使用 viewControllerInstance.ch.register() 这个方法,在大多数情况下,您可以在任何地方使用,但建议在出现这类问题时调用(可能导致调用顺序异常)

  • 3,主题切换函数或闭包调用顺序问题:

    • 父子视图(视图控制器)调用顺序:先调用子视图(视图控制器),再调用父视图(parent)
    • 对于单个视图(视图控制器):先调用主题切换函数,然后再尝试调用主题切换闭包
    • 视图和视图控制器调用顺序:在应用主题切换时,先调用视图的,然后才是视图控制器的
    • 视图控制器主题切换不会自动调用其视图的主题切换函数和闭包

迁移

版本 2.2 及以前的 API 不兼容,以下是一些重要修改:

  • 1. 移除函数 ch_switchTheme(_ now: Any, pre: Any?)
    • a. 重命名为 switchTheme(now: Any, pre: Any?)
  • 2. ThemeSwitchHelper 重命名为 ChameleonHelper   * a. 函数 currentTheme() 修改为属性 current
  • 3. ch_* 相关函数属性,修改为 ch.*

原理

采用扩展视图和视图控制器的形式实现。在主题切换时,通过遍历应用的视图和视图控制器树来切换主题。

广告

本库已经在某个新闻应用中使用,并经受了考验~