A tool that generate code for Swift projects, designed to improve the maintainability of UIColors

Overview

SwiftColorGen

Swift 4.0 CocoaPods compatible License

A tool that generate code for Swift projects, designed to improve the maintainability of UIColors.

Please notice, this tool still under development. It's on a validation phase, where I'll test it integrated with existing iOS projects to see how useful it is. Feedbacks are appreciated. Also notice this tool not only generates new code, but also updates existing storyboard files, so keep your code under versioning control to avoid any data loss!

Table of contents

Motivation

Manage colors in iOS projects can be challenging. It would be useful to reuse colors in different places in the storyboard and also access them programmatically. In code, you can group the colors in one place, but it's common to have the same color redefined in many places in the storyboards. When you need to update a color, you need to remember to replace them everywhere and because of that, it becomes hard to maintain.

Since Xcode 9, we are able to define a color asset in the Assets catalog, allowing us to reuse a color inside the storyboards and access them programmatically. Though, this still isn't perfect:

  1. To access the colors programmatically, we use a string with the Asset name. If we rename the Asset, we need to remember to replace the strings referring the old asset
  2. If we rename an Asset, we also need to manually replace the references to them in the storyboards
  3. In an existing project with no color assets defined, we need to group all the colors in the storyboards, manually create the asset colors and replace them everywhere.

The solution

SwiftColorGen reads all storyboard files to find common colors, it creates them in a .xcassets folder (without any duplications) and refer them back in the storyboard. Then, it creates an UIColor extension allowing to access the same colors programmatically. It automatically puts a name to the colors found. The name will be the closest webcolor name, measuring the color distance between them. But, the user still can rename the colors and it will keep the storyboards updated.

The rules for naming the colors dinamically:

  • The closest web color name (https://en.wikipedia.org/wiki/Web_colors) is considered to name the color
  • If the alpha value is less than 255, an "alpha suffix" will be appended to the color name, to avoid name collision
  • If two RGB's are close to the same web color, the name still will be used if they have different alphas
  • If two RGB's are close to the same web color and they also have the same alpha, the hex of the RGB will be used to avoid name collision

SwiftColorGen is written in Swift and requires Swift to run. These are the dependencies:

Demo

That's the result of the code generation:

Collecting the colors on Storyboard and generating the Assets

Collecting Colors

Generating the Swift file

Swift File

Automatic renaming

Automatic Renaming

Custom colors + multiple replace

Custom Colors

Code generated

The tool should generate something like:

// Don't change. Auto generated file. SwiftColorGen
import UIKit

extension UIColor {
    /// Color #FFC034 (alpha 255)
    static var goldColor: UIColor {
        return UIColor(named: "Gold") ?? .clear
    }

    /// Color #8D00FF (alpha 255)
    static var darkVioletColor: UIColor {
        return UIColor(named: "DarkViolet") ?? .clear
    }

    /// Color #00FF00 (alpha 255)
    static var myCoolGreen: UIColor {
        return UIColor(named: "MyCoolGreen") ?? .clear
    }
}

You will probably want to rename the color and run the tool again, but you can just create another extension on another file referring the generated code:

extension UIColor {
    static var myTextColor: UIColor {
        return .darkVioletColor
    }
}

Here a complete video with the tool in action:

Demo

Using the CLI

First, install the dependencies:

$ swift package update

Build it:

$ swift build

Then run passing the appropriate parameters (if you prefer, you can also use the binary generated inside the .build folder):

Usage: swift run SwiftColorGen [options]
-o --outputFile (required):
    Path to the output Swift file
-b --baseFolder (optional):
    Path to the folder where the storyboards are located. Defaults to the current working directory
-a --assetsFolder (optional):
    Path to the assets folder. Defaults to the first .xcassets found under the base folder

Example:

$ swift run SwiftColorGen -o Example/Generated.swift

Notice that OS X 10.12 is required to run, because of a dependency from a NSColor method (used to convert between different color spaces)

Installation

You can install the tool using CocoaPods and then add a Build Phase step, that runs SwiftColorGen every time the project is built.

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

  1. To integrate SwiftColorGen into your Xcode project, specify it in your Podfile:
pod 'SwiftColorGen'
  1. Install the dependencies:
$ pod install
  1. In Xcode: Click on your project in the file list, choose your target under TARGETS, click the Build Phases tab and add a New Run Script Phase by clicking the little plus icon in the top left. Drag the New Run Script Phase above the Compile Sources phase and below Check Pods Manifest.lock, expand it and then call the tool with something like that:
"$PODS_ROOT/SwiftColorGen/swiftcg" -b "$SRCROOT" -o "$SRCROOT/CustomColors.swift"
  1. Build your project and it's done. Remember to add the generated Swift file to Xcode, if it's not already there.

Contributing

This project still on a initial stage of development. Feel free to contribute by testing it and reporting bugs. If you want to help developing it, checkout the issues section. If you fixed some issue or made some enhancement, open a pull request.

License

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

Comments
  • Colors as Computed Properties

    Colors as Computed Properties

    I would prefer seeing the generated colours added as computed properties, as we are simply accessing a defined value of a particular type - and not doing any functional computation or state changing.

    opened by Gatada 2
  • Issue updating colors on the Assets catalog color picker

    Issue updating colors on the Assets catalog color picker

    Everything works fine if using the sRGB color space there, but other color spaces fails. The tool is ready to work with any color space but, this is not implemented on the Asset catalog itself. Just need to ensure, the values are persisted in sRGB converting from other color spaces (as done in the other places)

    bug help wanted 
    opened by fernandodelrio 1
  • Reduce storyboard number of changes

    Reduce storyboard number of changes

    The storyboard's XML is read, modified and then rewritten. The order of the tag's properties will probably change every time (AEXML won't keep the original order). This is bad considering that a diff will accuse a whole file difference on all storyboards, making a Code Review harder. Need to check if it's possible to rewrite the storyboard with the minimum of changes (with the diff only accusing the real changes made)

    enhancement help wanted 
    opened by fernandodelrio 1
  • Remove

    Remove "namedColor" duplicates that Xcode generates sometimes

    Sometimes when assigning a Named Color inside the storyboard, Xcode adds a duplicated entry for the same namedColor in the storyboard's xml. This can be easily seen, even without using this tool, just start assigning the same Named Color to different places, and you should see the duplicated entry in the xml.

    If you re-open the interface builder, Xcode should display a warning about that and then it will remove the duplicated entry. I found an open radar for that: https://openradar.appspot.com/35172913

    If we run SwiftColorGen, it will not remove the duplicated entry and when the Interface Builder reloads, the user will have the false impression, the tool introduced an error.

    Considering that, a enhancement can be made:

    Everytime SwiftGen runs, it should ensure there's no duplicates in the namedColor keys in the storyboard xml's.

    enhancement 
    opened by fernandodelrio 1
  • Invalid color functions generated

    Invalid color functions generated

    Two of the colors that got generated for my project were invalid/didn't compile:

    /// Color #FF0000 (alpha 217)
    class func genFF0000 (alpha 217)() -> UIColor {
    	return UIColor(named: "FF0000 (alpha 217)") ?? UIColor.white
    }
    
    /// Color #E00000 (alpha 217)
    class func genE00000 (alpha 217)() -> UIColor {
    	return UIColor(named: "E00000 (alpha 217)") ?? UIColor.white
    }
    

    Let me know what else would be helpful to debug

    bug 
    opened by schayes04 1
Releases(0.6.1)
Owner
Fernando del Rio
iOS Developer
Fernando del Rio
swiftUIviews is an online collection of beautifly designed swiftUIViews by the swift community

swiftUIViews | ?? swiftUIviews is an online collection of beautifly designed swiftUIViews by the swift community. Feelin like contributing? Follow the

emin 28 Aug 18, 2022
A simple integrated version of iOS 13 Compositional Layout, modified into a way similar to Functional Programming to generate UICollectionViewCompositionalLayout.

WWCompositionalLayout A simple integrated version of iOS 13 Compositional Layout, modified into a way similar to Functional Programming to generate UI

William-Weng 1 Jul 4, 2022
Build 1 scene, let AutoLayoutMagic generate the constraints for you!

Auto Layout Magic Create 1 scene, let Auto Layout Magic generate the constraints for you Hello friends, We've all been there. You have an app supporti

Matt 61 Sep 21, 2019
A mental health app designed to help users track their emotions with short, tweet-like journals.

Objective The purpose of this project is to create a mental health app where users will input a short journal each day that is no longer than a tweet

Isha Mahadalkar 0 Dec 25, 2021
Horizontal and Vertical collection view for infinite scrolling that was designed to be used in SwiftUI

InfiniteScroller Example struct ContentView: View { @State var selected: Int = 1 var body: some View { InfiniteScroller(direction: .ve

Serhii Reznichenko 5 Apr 17, 2022
UITableView based component designed to display a hierarchy of expandable/foldable comments.

SwiftyComments UITableView based component designed to display a hierarchy of expandable/foldable comments. Installation Manually Just copy the .swift

Stéphane Sercu 215 Sep 18, 2022
Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

Extremely Fast views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainabl

layoutBox 2k Sep 17, 2022
Written in pure Swift, QuickLayout offers a simple and easy way to manage Auto Layout in code.

QuickLayout QuickLayout offers an additional way, to easily manage the Auto Layout using only code. You can harness the power of QuickLayout to align

Daniel Huri 242 Sep 2, 2022
🎄 Advent of Code ’21 solutions in Swift

Advent of Code '21 My solutions to this years Advent of Code challenge written in Swift. Content Day 1: Sonar Sweep solution Day 2: Dive! solution Day

Witek Bobrowski 2 Dec 17, 2021
A Swift playgrounds with solutions of the Advent of Code 2021 challenge.

?? Advent of Code 2021 ?? A Swift playgrounds with solutions of the Advent of Code 2021. How to run Clone the repo and open the Playground in Xcode. S

Tommaso Madonia 1 Dec 20, 2021
A Code challenge I solved leveraging a lot on Composite collection view layout written in swift

AsthmApp Mobile app designed as a support aid for people with Asthma Accounts Google and Firebase [email protected] dICerytiMPSI Facebook asthmp.ap

null 0 Dec 13, 2021
A Code challenge I solved leveraging a lot on Composite collection view layout...written in swift

Space44 Code Challenge Space44 Code Challenge iOS application for Space 44 hiring process, it leverages on Image download and composite collection vie

null 0 Dec 16, 2021
Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast

Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

layoutBox 2k Sep 8, 2022
QR code generator in Swift, with no external dependencies.

QRDispenser is a lightweight library to generate a QR code as image (UIImage) in your app. It uses only native components, with no dependency from oth

Andrea Mario Lufino 10 Aug 30, 2022
Write less UI code

Layoutless Layoutless enables you to spend less time writing UI code. It provides a way to declaratively style and layout views. Here is an example of

Declarative Hub 429 Sep 10, 2022
Write concise Autolayout code

Winner of Hacking with Swift Recommended award You + Stevia = ?? ?? Write concise, readable layouts ?? Reduce your maintenance time ?? Compose your st

Fresh 3.3k Sep 17, 2022
An easier and faster way to code Autolayout

EZAnchor 中文介绍 An easier way to code Autolayout Are you annoyed of coding .active = true while using Autolayout Anchors over and over again? Are you an

Alex.Liu 25 Feb 20, 2022
The fast path to autolayout views in code

NorthLayout The fast path to autolayout views in code Talks https://speakerdeck.com/banjun/auto-layout-with-an-extended-visual-format-language at AltC

banjun 36 Jul 15, 2022
CompositionalLayoutDSL, library to simplify the creation of UICollectionViewCompositionalLayout. It wraps the UIKit API and makes the code shorter and easier to read.

CompositionalLayoutDSL CompositionalLayoutDSL is a Swift library. It makes easier to create compositional layout for collection view. Requirements Doc

FABERNOVEL 40 Sep 14, 2022