👕👚 Theme management in Swift

Overview

Themes

CI Status Version Carthage Compatible License Platform Swift

Story

Ever want to support Night mode? Or skin the app differently depending on the seasons? Or toggle features according to paid status? Well, those are actually reactions to app events.

Many other frameworks encourage you to use hard coded values, like label.xyz_textColors = [.red, .blue], textField.xyz_fonts = [font1, font2], .... This also makes it very hard to change because the usage of index, you need to remember that the 1st index is this theme, the 2nd index is that theme, ... Also, xyz_textColors is like trying to replicate the entire UIKit APIs, which updates often 😱

Themes is here to help. Usually, you have a finite number of colors and fonts in an app. You can have many more but that is not encourage and has design smells. When you have a theme, changing happens in one place.

Features

  • Universal support for iOS, macOS, tvOS, watchOS
  • Complete control over themes
  • Update existing views
  • Protocol oriented
  • Extensible

Usage

Step 1: Create a theme

Declare your theme by conforming to Theme, which is just a marker protocol. You can declare whatever you like, including nested objects, all depending on your need. You can also create as many themes as you like

struct MyTheme: Theme {
  let topImage: UIImage
  let cellColor: UIColor
  let backgroundColor: UIColor
  let name: String
  let titleFont: UIFont
  let subtitleFont: UIFont
}

Then create some themes based on your templates

let dayTheme = MyTheme(topImage: UIImage(named: "day"), cellColor: .white)
let nightTheme = MyTheme(topImage: UIImage(named: "night"), cellColor: .black)

The beauty of this is that you can init your theme from json, which can be fetched from backend 🚀

let json = [
  "primary_color": "#21ABE9",
  "font_name": "Chewy"
]
let unicornTheme = MyTheme(json)

Step 2: Register your current theme

When app launches, you need to declare 1 theme as the current, it can be loaded from cache

ThemeManager.shared.currentTheme = dayTheme

Step 3: React to theme change

You can do this wherever you like. It is set using the current theme, and whenever theme changes

// ViewController.swift
override func viewDidLoad() {
  super.viewDidLoad()

  use(MyTheme.self) {
    $0.title = $1.name
    $0.tableView.backgroundColor = $1.backgroundColor
    $0.navigationController?.navigationBar.setBackgroundImage($1.topImage, for: .default)
    $0.tableView.rowHeight = $1.name == "Unicorn" ? 180 : 120
    $0.tableView.reloadData()
  }
}

// Cell.swift
override func awakeFromNib() {
  super.awakeFromNib()

  imageView.layer.cornerRadius = 5
  imageView.layer.masksToBounds = true

  use(MyTheme.self) {
    $0.titleLabel.font = $1.titleFont
    $0.subtitleLabel.font = $1.subtitleFont
    $0.container.backgroundColor = $1.cellColor
  }
}

Step 4: Change the theme

Change the current theme is as easy as assigning a new theme. All happens in real time and very fast

ThemeManager.shared.currentTheme = nightTheme

Installation

Themes is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Themes'

Themes is also available through Carthage. To install just write into your Cartfile:

github "onmyway133/Themes"

Themes can also be installed manually. Just download and drop Sources folders in your project.

Author

Khoa Pham, [email protected]

Contributing

We would love you to contribute to Themes, check the CONTRIBUTING file for more info.

License

Themes is available under the MIT license. See the LICENSE file for more info.

Comments
  • Animating theme transition

    Animating theme transition

    What is the best way to add a transition when changing themes?

    For example, if I have a light and dark theme, and would like it to fade between the two when the ThemeManager.shared.currentTheme is changed.

    I am currently doing the following:

    view.use(MyTheme.self) { (view, theme) in
        UIView.animate(withDuration: 1.0, animations: {
            view.backgroundColor = theme.backgroundColor
        })
     }
    

    but would like to avoid having UIView.animate in every screen, as I'd like this behavior on all attributes.

    opened by malonehedges 3
  • Suggestion: rename API, clearer examples

    Suggestion: rename API, clearer examples

    Firstly, thank you for this project.

    I found it quite difficult to understand the usage and design of this framework, without having to go in to the code. Mostly, this was due to the framework's current naming practices.

    For example, I didn't know what a "Manager" was. Was it app-dependent? View-Controller dependent? What does it "manage"?

    To that end, I suggest changing the name to "ThemeManager" or "ThemesManager". And/or use a prefixing scheme.

    e.g. OMYThemesManager

    Similarly, the use of "theme()" is very problematic. e.g. given the following code:

    theme(MyTheme.self) {
        // ...
    }
    

    Some questions I had: where did this seemingly global method come from? What does it do? Am I creating a theme? Am I setting a theme? I have to use a "Manager" at one point, but I don't use Manager to set the theme? So if I don't have to use the Manager, and I have a theme, why don't I just call myTheme.set() ? Who does "theme()" belong to? Is it local, global? Part of a framework? etc. And why am I giving it a "MyTheme.self"? What is the action that occurs? These important questions can't be answered by the current naming scheme.

    Upshot: please consider renaming the API to use clearly readable nouns and verbs. The goal should be to make it crystal clear what any method/class will do.

    This problem also occurs in the Read Me example. You use a type called "MyTheme". This indicated to me that it was a one-off; a particular instance of a theme. In reality, it turned out to be a general type, designed for (possible) multiple use.

    It's hard to think of a good naming system for this kind of protocol adoption. The goal is to make it clear that the type itself is not the theme.

    Perhaps something like a "Template", which indicates that any given struct is designed for multiple use.

    e.g. given a project of name "Project":

    struct OnboardingThemeTemplate: OMYTheme {
      let topImage: UIImage
      let cellColor: UIColor
      let backgroundColor: UIColor
      let name: String
      let titleFont: UIFont
      let subtitleFont: UIFont
    }
    
    struct FeedbackThemeTemplate: OMYTheme {
      let backgroundColor: UIColor
      let name: String
      let titleFont: UIFont
      let subtitleFont: UIFont
    }
    
    struct ProjectThemes {
      static let onboarding = OnboardingThemeTemplate(...)
      static let mailFeedback = FeedbackThemeTemplate(...)
      static let twitterFeedback = FeedbackThemeTemplate(...)
      static let facebookFeedback = FeedbackThemeTemplate(...)
    }
    
    

    Or something like that. Hopefully you get the idea; a clear separation and identification of framework naming and other code.

    IMO, you should err on the side of readability, comprehension, rather than brevity and minimalism.

    Thank you.

    opened by SuperWomble 3
  • Can not run example because of lacking pod 'On'

    Can not run example because of lacking pod 'On'

    Hello, I think you remove your pod 'On'. It results in failing to run the example. Anw, I know how to use this pod without running the example. Thank you for your great effort.

    opened by vietstone-ng 0
  • Version 2.0.0 mission on CocoaPods

    Version 2.0.0 mission on CocoaPods

    I added Themes to my project and I noticed that the latest version on CocoaPods is not 2.0.0.

    Do you plan on continuing supporting this project / keep CocoaPods up to date?

    opened by WebMajstr- 2
  • A way to restore a previously selected theme.

    A way to restore a previously selected theme.

    Lets say a user selects a dark theme. When the user exits the app and relaunches, the theme resets to whatever is in code.

    Would be nice if the user's preference was persistence without the need for further implementations. I believe Themeable does this and would make a great feature.

    opened by multinerd 5
Releases(2.0.0)
Owner
Khoa
Check my apps https://onmyway133.com/apps
Khoa
🎨 Powerful theme/skin manager for iOS 9+ 主题/换肤, 暗色模式

Introduction - Demos - Installation - Documents - FAQ - Contribution - 中文文档 Screenshot Running:open SwiftTheme.xcworkspace, run target PlistDemo Intro

Gesen 2.4k Jan 1, 2023
A Publish theme. ckitakishi.com is built with PaletteTheme

PaletteTheme A Publish theme. ckitakishi.com is built with PaletteTheme. Features Simple and fast Mobile friendly Support both Light/Dark mode Customi

Yuhan Chen 10 Nov 29, 2022
This repository contains 🎨 My Xcode theme that I use. It is compatible with all versions of Xcode.

DRL Xcodetheme Installation Automatic (via script) ./install.sh which will install the file in Xcode FontAndColorThemes directory. Restart Xcode Go t

durul dalkanat 19 Oct 21, 2022
A powerful lightweight theme 🎨 manager for SwiftUI

SwiftTheming ?? is a handy lightweight handy theme manager which handles multiple themes based on system-wide appearances - light and dark appearances

Dscyre Scotti  38 Dec 29, 2022
Solarized Dark Theme for Xcode. Compatible with all modern versions of Xcode since 2013!

Solarized Dark for Xcode Note I've moved away from using Solarized to a Night-Shift/Dark-Mode-friendly palette of my own creation; Cognac. It's availa

Arthur Ariel Sabintsev 365 Nov 25, 2022
The official Swift style guide for raywenderlich.com.

The Official raywenderlich.com Swift Style Guide. Updated for Swift 5 This style guide is different from others you may see, because the focus is cent

raywenderlich 12.5k Dec 30, 2022
Style guide & coding conventions for Swift projects

This repository is no longer active. A guide to our Swift style and conventions. This is an attempt to encourage patterns that accomplish the followin

GitHub 4.8k Jan 4, 2023
A style guide for Swift.

Table Of Contents Overview Linter Standards Naming Conventions File Structure Types Statement Termination Variable Declaration Self Structs & Classes

Prolific Interactive 171 Oct 4, 2022
LinkedIn's Official Swift Style Guide

Swift Style Guide Make sure to read Apple's API Design Guidelines. Specifics from these guidelines + additional remarks are mentioned below. This guid

LinkedIn 1.4k Dec 13, 2022
A starter project for Sample Project in swift 5, Xcode 12.5

A starter project for Sample Project in swift 5, Xcode 12.5 (also bridging header included so you could use objective c code in it as well ).

Zeeshan Haider 51 Oct 27, 2022
Declarative view styling in Swift. Inspired by CSS modules.

Gaikan gives you powerful styling capabilities using a declarative DSL in Swift. Inspired by React: CSS in JS and CSS modules. To style UIView(s) just

null 141 Aug 23, 2021
Kushal Shingote 1 Feb 2, 2022
Theme handling macOS Appkit (Swift/Objective-C)

DSFAppearanceManager A class for simplifying macOS appearance values and detecting setting changes (Swift/Objective-C). Why? If you're performing cust

Darren Ford 8 Nov 1, 2022
FlexibleImage is implemented with the hope that anyone could easily develop an app that provides features such as Camera Filter and Theme.

FlexibleImage is implemented with the hope that anyone could easily develop an app that provides features such as Camera Filter and Theme. When you wr

Jungwon An 815 Dec 30, 2022
🎨 Powerful theme/skin manager for iOS 9+ 主题/换肤, 暗色模式

Introduction - Demos - Installation - Documents - FAQ - Contribution - 中文文档 Screenshot Running:open SwiftTheme.xcworkspace, run target PlistDemo Intro

Gesen 2.4k Jan 1, 2023
🧛🏻‍♂️ Dark theme for SwiftUI

Dracula for SwiftUI A dark theme for SwiftUI. Install All instructions can be found at draculatheme.com/swiftui. Team This theme is maintained by the

Dracula Theme 14 Jul 26, 2022
An unintrusive & light-weight iOS app-theming library with support for animated theme switching.

Gestalt Gestalt is an unintrusive and light-weight framework for application theming with support for animated theme switching. Usage Let's say you wa

Vincent Esche 327 Nov 8, 2022
SwiftUI module library for adding seasons theme animations to your app

HolidayThemes SwiftUI module library for adding seasons theme animations to your app. Requirements iOS 13.0+ Xcode 12.0+ Installation Swift Package Ma

null 2 Mar 7, 2022
A very simple soundboard that plays the first 5 seconds of the CSI Miami theme (YEAAAAAAAAAA)

MiamiSunglasses This app is a single-sound soundboard that plays the first few seconds of the CSI Miami theme song when you press the sunglasses. Disc

Adrian Edwards 4 Feb 10, 2022
A Publish theme. ckitakishi.com is built with PaletteTheme

PaletteTheme A Publish theme. ckitakishi.com is built with PaletteTheme. Features Simple and fast Mobile friendly Support both Light/Dark mode Customi

Yuhan Chen 10 Nov 29, 2022