What's New

More API additions and improvements!

2020-08-06T02:54:21Z
  • API Additions
    • Whether or not a focused node can be moved
    • Spawn area customization
    • Rotation speed customization
    • Determine if a node is being focused through isFocusing
    • The scene behind the view is now exposed for developers who want to delve deep into SpriteKit
  • Other
    • Selected nodes that are tapped again now inform the client
    • Added extra scaling animation to the default node style
    • Refined the focus animation

ElegantColorPalette

platforms pod Carthage compatible Swift Package Manager compatible License: MIT

The elegant color picker missed in UIKit and SwiftUI.

This example GIF is from ElegantTimeline. For a simpler demonstration, you can look at either of the 3 demo projects in this repository. And haha, that 2nd gif just me trying to tap as many nodes as fast as possible. And as you can see, there's no side effects.

Introduction

ElegantColorPalette comes with 24 different themes and is inspired by TimePage and is part of a larger repository of elegant demonstrations like this: TimePage Clone.

The top level view is an SKView that presents an SKScene of colors nodes. The color nodes are SKShapeNode subclasses. For more experienced developers that are or want to learn SpriteKit, the SKScene that contains the color nodes is exposed for greater fine tuning on your end.

Features

  • Dynamic color nodes - passing in a dynamic UIColor will allow the color node to properly adjust to light or dark mode
  • Extensive node customizability - font name, font color, node color, node radius, and much more
  • Custom node animations - snapping, scaling, fading, highlighting, and much more
  • Updating the color palette with new colors
  • Portait and landscape support
  • Extensively documentation - as you use the library, you'll notice documentation in XCode

Basic usage

For SwiftUI:

import ElegantColorPalette

struct ExampleSwiftUIView: View {

    @State private var selectedColor: PaletteColor = .kiwiGreen

    var body: some View {
        ColorPaletteBindingView(selectedColor: $selectedColor, colors: PaletteColor.allColors)
    }

}

For UIKit(programmatically):

import ElegantColorPalette

struct ExampleUIKitViewController: UIViewController {

    ...

    private lazy var paletteView: ColorPaletteView = {
        let paletteView = ColorPaletteView(colors: PaletteColor.allColors)
        paletteView.translatesAutoresizingMaskIntoConstraints = false
        return paletteView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        ...
        
        view.addSubview(paletteView)
        NSLayoutConstraint.activate([
            ...
        ])

        paletteView
            .didSelectColor { [unowned self] color in
                ...
            }
    }

}

For UIKit(storyboard and XIB):

import ElegantColorPalette

struct ExampleUIKitViewController: UIViewController {

    ...
    
    @IBOutlet weak var paletteView: ColorPaletteView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        ...
        
        paletteView
            .update(withColors: PaletteColor.allColors)
            .didSelectColor { [unowned self] color in
                ...
            }
    }

}

Customization

PaletteColor

PaletteColor represents the color model of a single node.

public struct PaletteColor: Equatable {

    public let name: String
    public let uiColor: UIColor

    public var color: Color {
        uiColor.asColor
    }

}

As you aren't able to get a UIColor from a Color in iOS 13, you must initialize a PaletteColor using a UIColor. If you are supporting light and dark color themes, you will want to pass a dynamic UIColor either through the asset bundle or other methods like a computed property.

For SwiftUI users, PaletteColor exposes a color property for your convenience.

Node Customization

Nodes are easily customizable through a number of node-modifier functions exposed the library itself. You can also make your own node-modifiers through NodeStyle and NodeModifier, like you would do in SwiftUI with ButtonStyle and ViewModifier.

See NodeConfiguration to better understand the various states of a node to determine when best to apply your modifier.

The following example demonstrates making a custom node style that further customizes the default node style. You must apply your custom modifiers to defaultStyledNode in order to retain the snap effect, highlighted border, etc you see in the demo gif. However, you are always free to start from scratch and style your own node for different states.

struct CustomNodeStyle: NodeStyle {

    func updateNode(configuration: Configuration) -> ColorNode {
        configuration.defaultStyledNode
            .radius(30)
            .font(name: "Thonburi")
    }

}

Creating your own node modifiers requires prerequisite knowledge of SKNode. Let's take a look at the ScaleFadeModifier. This modifier is responsible for scaling and fading the the node through SKActions.

struct ScaleFadeModifier: NodeModifier {

    let scale: CGFloat
    let opacity: CGFloat
    let animationDuration: TimeInterval

    func body(content: Content) -> ColorNode {
        let scaleAction = SKAction.scale(to: scale, duration: animationDuration)
        let opacityAction = SKAction.fadeAlpha(to: opacity, duration: animationDuration)

        content.run(.group([scaleAction, opacityAction]))

        return content
    }

}

To use your custom NodeStyle, pass it into the nodeStyle modifier:

// For UIKit
ColorPaletteView(...)
    .nodeStyle(CustomNodeStyle())
     
// For SwiftUI
ColorPaletteBindingView(...)
    .nodeStyle(CustomNodeStyle())

Focus Customization

Use focus to customize the location, speed, or smoothing rate of the focus animation.

// For UIKit
ColorPaletteView(...)
    .focus(location: .zero, speed: 1600, rate: 0.2)
     
// For SwiftUI
ColorPaletteBindingView(...)
    .focus(location: .zero, speed: 1600, rate: 0.2)

Use canMoveFocusedNode to customize whether the focused node is movable or not.

// For UIKit
ColorPaletteView(...)
    .canMoveFocusedNode(false)
     
// For SwiftUI
ColorPaletteBindingView(...)
    .canMoveFocusedNode(false)

For SwiftUI, you can also customize the binding animation that occurs when a new palette color is selected.

ColorPaletteBindingView(...)
    .bindingAnimation(.easeInOut)

Scene Customization

Like mentioned in the introduction, the SKScene that drives the view is exposed through a property called paletteScene. If you are experienced with SpriteKit, you may tamper with the scene for greater flexibility.

Use spawnConfiguration to customize the allowable area of where nodes can spawn:

// For UIKit
ColorPaletteView(...)
    .spawnConfiguration(widthRatio: 1, heightRatio: 1)
     
// For SwiftUI
ColorPaletteBindingView(...)
    .spawnConfiguration(widthRatio: 1, heightRatio: 1)

Use rotation to customize how fast you want the nodes to rotate around your focus location:

// For UIKit
ColorPaletteView(...)
    .rotation(multiplier: 4)
     
// For SwiftUI
ColorPaletteBindingView(...)
    .rotation(multiplier: 4)

Events

Use didSelectColor to react to any change of the selected palette color:

// For UIKit
ColorPaletteView(...)
     .didSelectColor { paletteColor in
         // do something
     }
     
// For SwiftUI
ColorPaletteBindingView(...)
     .didSelectColor { paletteColor in
         // do something
     }

Demos

There are 3 different demos, covering UIKit storyboards, XIBs and programmatic instantiation, and SwiftUI.

Requirements

  • iOS 13+(Statistics show that 90% of users are on iOS 13)
  • Xcode 11+
  • Swift 5.1+

Installation

ElegantColorPalette doesn't contain any external dependencies.

These are currently the supported installation options:

Manual

Inside Sources, drag the ElegantColorPalette folder into your project.

CocoaPods

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'ElegantColorPalette', '~> 1.2'
end

Replace YOUR_TARGET_NAME and then, in the Podfile directory, type:

$ pod install

Carthage

Add this to Cartfile

github "ThasianX/ElegantColorPalette" ~> 1.2.0
$ carthage update

Swift Package Manager

Using Xcode 11, go to File -> Swift Packages -> Add Package Dependency and enter https://github.com/ThasianX/ElegantColorPalette

If you are using Package.swift, you can also add ElegantColorPalette as a dependency easily.

// swift-tools-version:5.1

import PackageDescription

let package = Package(
  name: "TestProject",
  dependencies: [
    .package(url: "https://github.com/ThasianX/ElegantColorPalette", from: "1.2.0")
  ],
  targets: [
    .target(name: "TestProject", dependencies: ["ElegantColorPalette"])
  ]
)
$ swift build

Contributing

If you find a bug, or would like to suggest a new feature or enhancement, it'd be nice if you could search the issue tracker first; while we don't mind duplicates, keeping issues unique helps us save time and considates effort. If you can't find your issue, feel free to file a new one.

License

This project is licensed under the MIT License - see the LICENSE file for details

Description

  • Swift Tools 5.1.0
View More Packages from this Author

Dependencies

  • None
Last updated: Mon Oct 18 2021 11:09:18 GMT-0500 (GMT-05:00)