SwiftTheme 版本 0.6.4

SwiftTheme 版本 0.6.4

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2021 年 12 月
SPM支持 Swift Package Manager

GeSen 维护。



SwiftTheme 版本 0.6.4

  • 作者
  • Gesen

SwiftTheme

简介 - 示例 - 安装 - 文档 - 常见问题解答 - 贡献 - 中文文档

截图

运行:打开 SwiftTheme.xcworkspace,运行 PlistDemo 目标

简介

故事的开始

作为项目要求的一部分,我们需要在我们的应用中添加夜间模式。这不仅只是更改顶级视图的亮度和 alpha 值那么简单——实际上,它需要一个全新的界面:不同的颜色、不同的 alpha 值、不同的图像裁剪。更准确地说,“夜间模式”是一种可以切换亮色主题和暗色主题的主题/皮肤功能。

那么我们如何实现这一点呢?也许我们可以设置一个全局变量来表示当前选定的主题,并在控制器初始化期间根据该变量使用不同的背景颜色或图像裁剪。但那么我们如何处理已经初始化的视图呢?是的,我们可以使用通知来更改它们的颜色或图像裁剪,但这会导致控制器中充斥着不必要的通知注册/注销、if...else 和 UI 更新代码。更糟的是,如果你忘记取消注册通知,你的应用可能会崩溃。

经过一番考虑,我们对任务提出了更高的要求:创建一个简单且可重用的主题/皮肤框架,如下所示。

目标

将SwiftTheme打造为一个简单、强大、高性能、可扩展的主题/皮肤框架。为iOS提供统一解决方案。

演示

索引模式

根据主题设置更改UIView的背景色

view.theme_backgroundColor = ["#FFF", "#000"]

根据主题设置更改UILabel和UIButton的文本色

label.theme_textColor = ["#000", "#FFF"]
button.theme_setTitleColor(["#000", "#FFF"], forState: .Normal)

根据主题设置更改UIImageView的图片

imageView.theme_image = ["day", "night"]

// It's ok by using UIImage instances if you don't want to use image names.
imageView.theme_image = ThemeImagePicker(images: image1, image2)

执行下面单行代码后,即可呈现神奇效果!

// these numbers represent the parameters' index. 
// eg. "view.theme_backgroundColor = ["#FFF", "#000"]", index 0 represents "#FFF", index 1 represents "#000"
ThemeManager.setTheme(index: isNight ? 1 : 0)

获取当前主题索引。

ThemeManager.currentThemeIndex	// Readonly

索引模式适合以下情况:主题数量不多,无需下载更多新主题。

关于字面量的注意事项

// Wrong example:
let colors = ["#FFF", "#000"]
view.theme_backgroundColor = colors

// You should write like this:
view.theme_backgroundColor = ["#FFF", "#000"]
// or this:
let colorPickers: ThemeColorPicker = ["#FFF", "#000"]
view.theme_backgroundColor = colorPickers

因为theme_backgroundColor接受ThemeColorPicker类型的参数,而不是数组。不过,“view.theme_backgroundColor = ['#FFF', '#000']”与通过“字面量”初始化ThemeColorPicker实例并将其传递给theme_backgroundColor的效果相同。

Plist/JSON模式

您可能想让您的应用下载并安装不定数量的主题。为了满足这一需求,我们提供了plist模式。简单地说,您只需要在一个plist文件中写入配置信息,如颜色、图像裁剪等,然后您可以在逻辑代码中使用这些键。因此,plist文件和资源文件共同构成了主题包。

plist模式的用法演示。

view.theme_backgroundColor = "Global.backgroundColor"
imageView.theme_image = "SelectedThemeCell.iconImage"

与索引模式类似。只是具体参数变为键。因此,我们赋予了它扩展能力。

在切换方法中,plist文件名是第一个参数。在本例中,plist文件和其他资源文件位于应用包中。如果它们在沙箱中,也完全可以。

ThemeManager.setTheme(plistName: "Red", path: .mainBundle)

plist模式允许您在不修改逻辑代码的情况下安装更多主题。因此,您可以添加下载和安装应用主题的功能。

上述所使用的plist和图片文件的截图

Objective-C

完全兼容Objective-C,使用演示

lbl.theme_backgroundColor = [ThemeColorPicker pickerWithColors:@[@"#FAF9F9", @"#E2E2E2"]];

特性

  • 用Swift编写的
  • 完全兼容Objective-C
  • 基于运行时
  • 简单集成
  • 扩展属性前缀为"theme_*",与IDE自动完成友好
  • 支持UIAppearance
  • 索引模式,快速集成
  • plist模式,扩展无限主题
  • 友好的错误日志
  • 强类型ThemePicker,检测编译过程中的错误
  • 完整的演示

安装

CocoaPods

pod 'SwiftTheme'
use_frameworks!

Carthage

github "wxxsw/SwiftTheme"

Swift包管理器

  1. 选择 Xcode -> 文件 -> Swift包 -> 添加包依赖...
  2. 输入 https://github.com/wxxsw/SwiftTheme.
  3. 点击 下一步,然后选择版本,完成。

源文件

将“源”文件夹中的所有文件复制到您的项目中

文档

注意: 索引模式的用法 Plist模式的用法

基本用法


配置外观

SwiftTheme为视图提供了新的属性,它们都以theme_开头。例如,theme_backgroundColor对应backgroundColor

①
view.theme_backgroundColor = ThemeColorPicker(colors: "#FFF", "#000")
view.theme_image = ThemeImagePicker(names: "day", "night")
②
view.theme_backgroundColor = ThemeColorPicker(keyPath: "SomeColorKeyPath")
view.theme_image = ThemeImagePicker(keyPath: "SomeImageKeyPath")

不同类型的属性接收不同类型的拾取器。因此,IDE会在您传递错误的参数时警告您。

切换主题

切换主题时,您设置的theme_属性将带有动画更新。用法

①
ThemeManager.setTheme(index: 0) // ThemePickers will use the first parameter, eg. "#FFF" "day"
ThemeManager.setTheme(index: 1) // ThemePickers will use the second parameter, eg. "#000" "night"
// use "day.plist" in the appllication bundle as the theme configuration file. 
// In this mode, SwiftTheme will find the resource files in the appllication bundle.
ThemeManager.setTheme(plistName: "day", path: .mainBundle)
// use "night.plist" in the sandbox as the theme configuration file, "someURL" is its file path. 
// In this mode, SwiftTheme will find the resource files in the same path.
ThemeManager.setTheme(plistName: "night", path: .sandbox(someURL))
// use a dictionary as the theme configuration, but find resource files in the sandbox.(Not recommend)
ThemeManager.setTheme(dict: dict, path: .sandbox(someURL))

自定义行为

当主题更改时,SwiftTheme会发布名为ThemeUpdateNotification的通知,您可以在任何地方观察到这个通知并执行任何操作。

NotificationCenter.default.addObserver(
	self, 
	selector: #selector(doSomethingMethod),
	name: NSNotification.Name(rawValue: ThemeUpdateNotification), 
	object: nil
)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomethingMethod) name:@"ThemeUpdateNotification" object:nil];

当前支持属性


子类继承自父类的属性,例如UILabel类继承自UIView类的theme_alpha属性。以下子类中不会列出这些属性。

UIView
  • var theme_alpha: ThemeCGFloatPicker?
  • var theme_backgroundColor: ThemeColorPicker?
  • var theme_tintColor: ThemeColorPicker?
UIApplication
  • func theme_setStatusBarStyle(picker: ThemeStatusBarStylePicker, animated: Bool)
UIBarButtonItem
  • var theme_tintColor: ThemeColorPicker?
UILabel
  • var theme_font: ThemeFontPicker?
  • var theme_textColor: ThemeColorPicker?
  • var theme_textAttributes: ThemeStringAttributesPicker?
  • var theme_highlightedTextColor: ThemeColorPicker?
  • var theme_shadowColor: ThemeColorPicker?
UINavigationBar
  • var theme_barStyle: ThemeBarStylePicker?
  • var theme_barTintColor: ThemeColorPicker?
  • var theme_titleTextAttributes: ThemeDictionaryPicker?
UITabBar
  • var theme_barStyle: ThemeBarStylePicker?
  • var theme_barTintColor: ThemeColorPicker?
UITableView
  • var theme_separatorColor: ThemeColorPicker?
UITextField
  • var theme_font: ThemeFontPicker?
  • var theme_keyboardAppearance: ThemeKeyboardAppearancePicker?
  • var theme_textColor: ThemeColorPicker?
  • var theme_placeholderAttributes: ThemeDictionaryPicker?
UITextView
  • var theme_font: ThemeFontPicker?
  • var theme_textColor: ThemeColorPicker?
UIToolbar
  • var theme_barStyle: ThemeBarStylePicker?
  • var theme_barTintColor: ThemeColorPicker?
UISegmentedControl
  • var theme_selectedSegmentTintColor: ThemeColorPicker?
  • func theme_setTitleTextAttributes(_ picker: ThemeStringAttributesPicker?, forState state: UIControl.State)
UISwitch
  • var theme_onTintColor: ThemeColorPicker?
  • var theme_thumbTintColor: ThemeColorPicker?
UISlider
  • var theme_thumbTintColor: ThemeColorPicker?
  • var theme_minimumTrackTintColor: ThemeColorPicker?
  • var theme_maximumTrackTintColor: ThemeColorPicker?
UISearchBar
  • var theme_barStyle: ThemeBarStylePicker?
  • var theme_barTintColor: ThemeColorPicker?
UIProgressView
  • var theme_progressTintColor: ThemeColorPicker?
  • var theme_trackTintColor: ThemeColorPicker?
UIPageControl
  • var theme_pageIndicatorTintColor: ThemeColorPicker?
  • var theme_currentPageIndicatorTintColor: ThemeColorPicker?
UIImageView
  • var theme_image: ThemeImagePicker?
UIActivityIndicatorView
  • var theme_activityIndicatorViewStyle: ThemeActivityIndicatorViewStylePicker?
UIButton
  • 函数 theme_setImage(picker: ThemeImagePicker?,forState state: UIControlState)
  • 函数 theme_setBackgroundImage(picker: ThemeImagePicker?,forState state: UIControlState)
  • 函数 theme_setTitleColor(picker: ThemeColorPicker?,forState state: UIControlState)
  • 函数 theme_setAttributedTitle(picker: ThemeAttributedStringPicker?,forState state: UIControlState)
CALayer
  • 变量 theme_backgroundColor: ThemeCGColorPicker?
  • 变量 theme_borderWidth: ThemeCGFloatPicker?
  • 变量 theme_borderColor: ThemeCGColorPicker?
  • 变量 theme_shadowColor: ThemeCGColorPicker?
CATextLayer
  • 变量 theme_foregroundColor: ThemeCGColorPicker?
CAGradientLayer
  • 变量 theme_colors: ThemeAnyPicker?
UIRefreshControl
  • 变量 theme_titleAttributes: ThemeDictionaryPicker?
UIVisualEffectView
  • 变量 theme_effect: ThemeVisualEffectPicker?

选择器


主题颜色选择器

// supported formats:
// "#ffcc00"		RGB
// "#ffcc00dd"		RGBA
// "#FFF"			RGB in short
// "#013E"			RGBA in short
ThemeColorPicker(colors: "#FFFFFF", "#000")
ThemeColorPicker(colors: UIColor.red, UIColor.blue)
ThemeColorPicker.pickerWithColors(["#FFFFFF", "#000"])
ThemeColorPicker.pickerWithUIColors([UIColor.red, UIColor.blue])
②
ThemeColorPicker(keyPath: "someStringKeyPath")
ThemeColorPicker.pickerWithKeyPath("someStringKeyPath")

主题图片选择器

ThemeImagePicker(names: "image1", "image2")
ThemeImagePicker.pickerWithNames(["image1", "image2"])
ThemeImagePicker(images: UIImage(named: "image1")!, UIImage(named: "image2")!)
ThemeImagePicker.pickerWithImages([UIImage(named: "image1")!, UIImage(named: "image2")!])
②
ThemeImagePicker(keyPath: "someStringKeyPath")
ThemeImagePicker.pickerWithKeyPath("someStringKeyPath")

主题浮点选择器

ThemeCGFloatPicker(floats: 1.0, 0.7)
ThemeCGFloatPicker.pickerWithFloats([1.0, 0.7])
②
ThemeCGFloatPicker(keyPath: "someNumberKeyPath")
ThemeCGFloatPicker.pickerWithKeyPath("someNumberKeyPath")

主题颜色选择器

ThemeCGColorPicker(colors: "#FFFFFF", "#000")
ThemeCGColorPicker(colors: UIColor.red, UIColor.blue)
ThemeCGColorPicker(colors: UIColor.red.cgColor, UIColor.blue.cgColor)
ThemeCGColorPicker.pickerWithColors(["#FFFFFF", "#000"])
ThemeCGColorPicker.pickerWithUIColors([UIColor.blue, UIColor.red])
②
ThemeCGColorPicker(keyPath: "someStringKeyPath")
ThemeCGColorPicker.pickerWithKeyPath("someStringKeyPath")

主题字体选择器

ThemeFontPicker(fonts: UIFont.systemFont(ofSize: 10), UIFont.systemFont(ofSize: 11))
ThemeFontPicker.pickerWithFonts([UIFont.systemFont(ofSize: 10), UIFont.systemFont(ofSize: 11)])
②
// name the key you like, but the available values format like this: "PingFangSC-Regular,16"
ThemeFontPicker(keyPath: "someStringKeyPath")
ThemeFontPicker.pickerWithKeyPath("someStringKeyPath")

主题字典选择器

ThemeDictionaryPicker(dicts: ["key": "value"], ["key": "value"])
ThemeDictionaryPicker.pickerWithDicts([["key": "value"], ["key": "value"]])
②
ThemeDictionaryPicker(keyPath: "someStringKeyPath") { (Any?) -> [String: AnyObject]? in ... }

主题字符串属性选择器

ThemeStringAttributesPicker(["key": "value"], ["key": "value"])
ThemeStringAttributesPicker.pickerWithAttributes([NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)])
②
ThemeStringAttributesPicker(keyPath: "someStringKeyPath") { (Any?) -> [NSAttributedString.Key: Any]? in ... }

主题属性字符串选择器

ThemeAttributedStringPicker(NSAttributedString(...), NSAttributedString(...))
ThemeAttributedStringPicker.pickerWithAttributedStrings([NSAttributedString(...)])
②
ThemeAttributedStringPicker(keyPath: "someStringKeyPath") { (Any?) -> NSAttributedString? in ... }

主题栏样式选择器

ThemeBarStylePicker(styles: .default, .black)
ThemeBarStylePicker.pickerWithStyles([.default, .black])
ThemeBarStylePicker.pickerWithStringStyles(["default", "black"])
②
// name the key you like, but the available values are "default" and "black"
ThemeBarStylePicker(keyPath: "someStringKeyPath")
ThemeBarStylePicker.pickerWithKeyPath("someStringKeyPath")

主题状态栏样式选择器

ThemeStatusBarStylePicker(styles: .default, .lightContent, .darkContent)
ThemeStatusBarStylePicker.pickerWithStyles([.default, .lightContent, .darkContent])
ThemeStatusBarStylePicker.pickerWithStringStyles(["default", "lightContent", "darkContent"])
②
// name the key you like, but the available values are "default", "lightContent" and "darkContent"
ThemeStatusBarStylePicker(keyPath: "someStringKeyPath")
ThemeStatusBarStylePicker.pickerWithKeyPath("someStringKeyPath")

主题键盘外观选择器

ThemeKeyboardAppearancePicker(styles: .default, .dark, .light)
ThemeKeyboardAppearancePicker.pickerWithStyles([.default, .dark, .light])
ThemeKeyboardAppearancePicker.pickerWithStringStyles(["default", "dark", "light"])
②
// name the key you like, but the available values are "default", "dark" and "light"
ThemeKeyboardAppearancePicker(keyPath: "someStringKeyPath")
ThemeKeyboardAppearancePicker.pickerWithKeyPath("someStringKeyPath")

主题活动指示器视图样式选择器

ThemeActivityIndicatorViewStylePicker(styles: .whiteLarge, .white, .gray)
ThemeActivityIndicatorViewStylePicker.pickerWithStyles([.whiteLarge, .white, .gray])
ThemeActivityIndicatorViewStylePicker.pickerWithStringStyles(["whiteLarge", "white", "gray"])
②
// name the key you like, but the available values are "whiteLarge", "white" and "gray"
ThemeActivityIndicatorViewStylePicker(keyPath: "someStringKeyPath")
ThemeActivityIndicatorViewStylePicker.pickerWithKeyPath("someStringKeyPath")

主题视觉效果选择器

ThemeVisualEffectPicker(effects: UIBlurEffect(style: .light), UIBlurEffect(style: .dark))
ThemeVisualEffectPicker.pickerWithEffects([UIBlurEffect(style: .light), UIBlurEffect(style: .dark)])
ThemeVisualEffectPicker.pickerWithStringEffects(["light", "dark", "extralight", "prominent", "regular"])
②
// name the key you like, but the available values are "light", "dark", "extralight", "prominent" and "regular"
ThemeVisualEffectPicker(keyPath: "someStringKeyPath")
ThemeVisualEffectPicker.pickerWithKeyPath("someStringKeyPath")

ThemeAnyPicker

ThemeAnyPicker(anys: 0, "123", UIColor.red)
ThemeAnyPicker.pickerWithAnys([0, "123", UIColor.red])
②
ThemeAnyPicker(keyPath: "someStringKeyPath")
ThemeAnyPicker.pickerWithKeyPath("someStringKeyPath")

更多

下载此项目并探索更多。有四个演示目标

  • Demo 演示了如何使用索引模式以及如何保存主题的最后选择和其他通用用法。
  • PlistDemo 演示了如何使用 plist 模式以及如何下载打包在 zip 文件中的主题。
  • JsonDemoPlistDemo 类似,但使用 json
  • OCDemoDemo 的 Objective-C 版本。
  • TVOSDemo 用于测试 tvos 兼容性。

常见问题解答

  1. 为什么 theme_setStatusBarStyle 无法按预期工作?

    在您的应用的 Info.plist 中,您需要将 View Controller-based status bar appearance 设置为 NO

  2. 我能否手动取消一个属性的样式?

    当然可以,只需将其置为 nil——例如:view.theme_backgroundColor = nil

贡献

问题

如果您发现错误或需要帮助,您可以在 创建问题

拉取请求

我们很高兴接受pull请求:D。但请确保大多数开发者都需要它,并且使用起来要简单。如果您不确定,请创建一个问题,我们可以在您开始编码之前讨论。

贡献者

Gesen, Zhoujun, Kevin Cramer

许可证

MIT许可证(MIT)