mirror of
https://github.com/joncardasis/ChromaColorPicker.git
synced 2024-08-16 01:50:30 +03:00
Resolved issue with handleSize. Added additional tests. Example homeHandle now changes tint based on lightness of selected color
This commit is contained in:
parent
7191d098d0
commit
8bf9b34f9b
@ -15,6 +15,8 @@
|
|||||||
35C376D61D5CF5300069D7A1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D41D5CF5300069D7A1 /* Main.storyboard */; };
|
35C376D61D5CF5300069D7A1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D41D5CF5300069D7A1 /* Main.storyboard */; };
|
||||||
35C376D81D5CF5300069D7A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D71D5CF5300069D7A1 /* Assets.xcassets */; };
|
35C376D81D5CF5300069D7A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D71D5CF5300069D7A1 /* Assets.xcassets */; };
|
||||||
35C376DB1D5CF5300069D7A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D91D5CF5300069D7A1 /* LaunchScreen.storyboard */; };
|
35C376DB1D5CF5300069D7A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D91D5CF5300069D7A1 /* LaunchScreen.storyboard */; };
|
||||||
|
C83A935D23760C1600564E01 /* UIColor+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83A935C23760C1600564E01 /* UIColor+Utils.swift */; };
|
||||||
|
C83A936023760C5900564E01 /* UIColor+UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83A935E23760C3800564E01 /* UIColor+UtilsTests.swift */; };
|
||||||
FC1BD8C02207D7B700817AF3 /* ChromaColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */; };
|
FC1BD8C02207D7B700817AF3 /* ChromaColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */; };
|
||||||
FC1BD8C22207D7B700817AF3 /* ChromaColorPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3503B82F1F2689BC00750356 /* ChromaColorPicker.framework */; };
|
FC1BD8C22207D7B700817AF3 /* ChromaColorPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3503B82F1F2689BC00750356 /* ChromaColorPicker.framework */; };
|
||||||
FC4387C422603AE900F739F1 /* ColorWheelViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42AB226038A400BE2FF9 /* ColorWheelViewTests.swift */; };
|
FC4387C422603AE900F739F1 /* ColorWheelViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42AB226038A400BE2FF9 /* ColorWheelViewTests.swift */; };
|
||||||
@ -87,6 +89,8 @@
|
|||||||
35C376D71D5CF5300069D7A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
35C376D71D5CF5300069D7A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
35C376DA1D5CF5300069D7A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
35C376DA1D5CF5300069D7A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
35C376DC1D5CF5300069D7A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
35C376DC1D5CF5300069D7A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
C83A935C23760C1600564E01 /* UIColor+Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Utils.swift"; sourceTree = "<group>"; };
|
||||||
|
C83A935E23760C3800564E01 /* UIColor+UtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+UtilsTests.swift"; sourceTree = "<group>"; };
|
||||||
FC1BD8BD2207D7B700817AF3 /* ChromaColorPickerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChromaColorPickerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
FC1BD8BD2207D7B700817AF3 /* ChromaColorPickerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChromaColorPickerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChromaColorPickerTests.swift; sourceTree = "<group>"; };
|
FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChromaColorPickerTests.swift; sourceTree = "<group>"; };
|
||||||
FC1BD8C12207D7B700817AF3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
FC1BD8C12207D7B700817AF3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
@ -215,6 +219,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FC4387DC226972EB00F739F1 /* UIColor+Brightness.swift */,
|
FC4387DC226972EB00F739F1 /* UIColor+Brightness.swift */,
|
||||||
|
C83A935C23760C1600564E01 /* UIColor+Utils.swift */,
|
||||||
FCCA42A92260329900BE2FF9 /* UIView+DropShadow.swift */,
|
FCCA42A92260329900BE2FF9 /* UIView+DropShadow.swift */,
|
||||||
FC89B7E32325C24F00D007AB /* UIView+Utils.swift */,
|
FC89B7E32325C24F00D007AB /* UIView+Utils.swift */,
|
||||||
);
|
);
|
||||||
@ -225,6 +230,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FCE07BFD227B4A8100920217 /* UIColor+BrightnessTests.swift */,
|
FCE07BFD227B4A8100920217 /* UIColor+BrightnessTests.swift */,
|
||||||
|
C83A935E23760C3800564E01 /* UIColor+UtilsTests.swift */,
|
||||||
FCE07C03227B4DB900920217 /* UIView+DropShadowTests.swift */,
|
FCE07C03227B4DB900920217 /* UIView+DropShadowTests.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
@ -405,6 +411,7 @@
|
|||||||
FCCA42AA2260329900BE2FF9 /* UIView+DropShadow.swift in Sources */,
|
FCCA42AA2260329900BE2FF9 /* UIView+DropShadow.swift in Sources */,
|
||||||
FC4387DE226974FD00F739F1 /* UIColor+Brightness.swift in Sources */,
|
FC4387DE226974FD00F739F1 /* UIColor+Brightness.swift in Sources */,
|
||||||
FC4387C62262556600F739F1 /* ChromaBrightnessSlider.swift in Sources */,
|
FC4387C62262556600F739F1 /* ChromaBrightnessSlider.swift in Sources */,
|
||||||
|
C83A935D23760C1600564E01 /* UIColor+Utils.swift in Sources */,
|
||||||
FCCA42A7226023F000BE2FF9 /* ChromaColorHandle.swift in Sources */,
|
FCCA42A7226023F000BE2FF9 /* ChromaColorHandle.swift in Sources */,
|
||||||
FCCA42A5226022A800BE2FF9 /* ColorWheelView.swift in Sources */,
|
FCCA42A5226022A800BE2FF9 /* ColorWheelView.swift in Sources */,
|
||||||
FC4387C922625C7000F739F1 /* SliderTrackView.swift in Sources */,
|
FC4387C922625C7000F739F1 /* SliderTrackView.swift in Sources */,
|
||||||
@ -426,6 +433,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
FCE07C06227B525000920217 /* ChromaControlStylableTests.swift in Sources */,
|
FCE07C06227B525000920217 /* ChromaControlStylableTests.swift in Sources */,
|
||||||
|
C83A936023760C5900564E01 /* UIColor+UtilsTests.swift in Sources */,
|
||||||
FC89B7E02325B07F00D007AB /* ChromaBrightnessSliderTests.swift in Sources */,
|
FC89B7E02325B07F00D007AB /* ChromaBrightnessSliderTests.swift in Sources */,
|
||||||
FC89B7E22325B8B900D007AB /* FakeTouch.swift in Sources */,
|
FC89B7E22325B8B900D007AB /* FakeTouch.swift in Sources */,
|
||||||
FCE07C0C228A0F7500920217 /* ChromaColorHandleTests.swift in Sources */,
|
FCE07C0C228A0F7500920217 /* ChromaColorHandleTests.swift in Sources */,
|
||||||
|
@ -22,6 +22,13 @@ class ViewController: UIViewController {
|
|||||||
setupColorPickerHandles()
|
setupColorPickerHandles()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||||
|
return .lightContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
private var homeHandle: ChromaColorHandle! // reference to home handle
|
||||||
|
|
||||||
private func setupColorPicker() {
|
private func setupColorPicker() {
|
||||||
colorPicker.delegate = self
|
colorPicker.delegate = self
|
||||||
colorPicker.translatesAutoresizingMaskIntoConstraints = false
|
colorPicker.translatesAutoresizingMaskIntoConstraints = false
|
||||||
@ -57,14 +64,24 @@ class ViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setupColorPickerHandles() {
|
private func setupColorPickerHandles() {
|
||||||
|
// (Optional) Assign a custom handle size - all handles appear as the same size
|
||||||
|
// colorPicker.handleSize = CGSize(width: 48, height: 60)
|
||||||
|
|
||||||
|
// 1. Add handle and then customize
|
||||||
addHomeHandle()
|
addHomeHandle()
|
||||||
|
|
||||||
|
// 2. Add a handle via a color
|
||||||
let peachColor = UIColor(red: 1, green: 203 / 255, blue: 164 / 255, alpha: 1)
|
let peachColor = UIColor(red: 1, green: 203 / 255, blue: 164 / 255, alpha: 1)
|
||||||
colorPicker.addHandle(at: peachColor)
|
colorPicker.addHandle(at: peachColor)
|
||||||
|
|
||||||
|
// 3. Create a custom handle and add to picker
|
||||||
|
let customHandle = ChromaColorHandle()
|
||||||
|
customHandle.color = UIColor.purple
|
||||||
|
colorPicker.addHandle(customHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addHomeHandle() {
|
private func addHomeHandle() {
|
||||||
let homeHandle = colorPicker.addHandle(at: .blue)
|
homeHandle = colorPicker.addHandle(at: .blue)
|
||||||
|
|
||||||
// Setup custom handle view with insets
|
// Setup custom handle view with insets
|
||||||
let customImageView = UIImageView(image: #imageLiteral(resourceName: "home").withRenderingMode(.alwaysTemplate))
|
let customImageView = UIImageView(image: #imageLiteral(resourceName: "home").withRenderingMode(.alwaysTemplate))
|
||||||
@ -78,8 +95,18 @@ class ViewController: UIViewController {
|
|||||||
extension ViewController: ChromaColorPickerDelegate {
|
extension ViewController: ChromaColorPickerDelegate {
|
||||||
func colorPickerHandleDidChange(_ colorPicker: ChromaColorPicker, handle: ChromaColorHandle, to color: UIColor) {
|
func colorPickerHandleDidChange(_ colorPicker: ChromaColorPicker, handle: ChromaColorHandle, to color: UIColor) {
|
||||||
colorDisplayView.backgroundColor = color
|
colorDisplayView.backgroundColor = color
|
||||||
|
|
||||||
|
// Here I can detect when the color is too bright to show a white icon
|
||||||
|
// on the handle and change its tintColor.
|
||||||
|
if handle === homeHandle, let imageView = homeHandle.accessoryView as? UIImageView {
|
||||||
|
let colorIsBright = color.isLight
|
||||||
|
print(color.lightness)
|
||||||
|
|
||||||
|
UIView.animate(withDuration: 0.2, animations: {
|
||||||
|
imageView.tintColor = colorIsBright ? .black : .white
|
||||||
|
}, completion: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// ChromaColorPicker2.swift
|
// ChromaColorPicker.swift
|
||||||
// ChromaColorPicker
|
// ChromaColorPicker
|
||||||
//
|
//
|
||||||
// Created by Jon Cardasis on 3/10/19.
|
// Created by Jon Cardasis on 3/10/19.
|
||||||
@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Accelerate
|
|
||||||
|
|
||||||
public protocol ChromaColorPickerDelegate: class {
|
public protocol ChromaColorPickerDelegate: class {
|
||||||
/// When a handle's value has changed.
|
/// When a handle's value has changed.
|
||||||
@ -41,7 +40,7 @@ public class ChromaColorPicker: UIControl, ChromaControlStylable {
|
|||||||
|
|
||||||
/// The size handles should be displayed at.
|
/// The size handles should be displayed at.
|
||||||
public var handleSize: CGSize = defaultHandleSize {
|
public var handleSize: CGSize = defaultHandleSize {
|
||||||
didSet { layoutNow() }
|
didSet { setNeedsLayout() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An extension to handles' hitboxes in the +Y direction.
|
/// An extension to handles' hitboxes in the +Y direction.
|
||||||
|
28
Source/Extensions/UIColor+Utils.swift
Normal file
28
Source/Extensions/UIColor+Utils.swift
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// UIColor+Utils.swift
|
||||||
|
// ChromaColorPicker
|
||||||
|
//
|
||||||
|
// Created by Jonathan Cardasis on 11/8/19.
|
||||||
|
// Copyright © 2019 Jonathan Cardasis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public extension UIColor {
|
||||||
|
|
||||||
|
/// The value of lightness a color has. Value between [0.0, 1.0]
|
||||||
|
/// Based on YIQ color space for constrast (https://www.w3.org/WAI/ER/WD-AERT/#color-contrast)
|
||||||
|
var lightness: CGFloat {
|
||||||
|
var red: CGFloat = 0
|
||||||
|
var green: CGFloat = 0
|
||||||
|
var blue: CGFloat = 0
|
||||||
|
getRed(&red, green: &green, blue: &blue, alpha: nil)
|
||||||
|
|
||||||
|
return ((red * 299) + (green * 587) + (blue * 114)) / 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether or not the color is considered 'light' in terms of contrast.
|
||||||
|
var isLight: Bool {
|
||||||
|
return lightness >= 0.5
|
||||||
|
}
|
||||||
|
}
|
@ -190,6 +190,49 @@ class ChromaColorPickerTests: XCTestCase {
|
|||||||
// Then
|
// Then
|
||||||
XCTAssertTrue(eventDidTrigger)
|
XCTAssertTrue(eventDidTrigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testHitTestShouldReturnSelfWhenTouchIsWithinSelf() {
|
||||||
|
subject.colorWheelView.layoutIfNeeded()
|
||||||
|
|
||||||
|
// Given
|
||||||
|
let touchLocation = subject.center
|
||||||
|
|
||||||
|
// When
|
||||||
|
let hitView = subject.hitTest(touchLocation, with: UIEvent())
|
||||||
|
|
||||||
|
// Then
|
||||||
|
XCTAssertEqual(hitView, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHitTestShouldReturnSelfWhenTouchIsWithinSelfPlusHandleRadius() {
|
||||||
|
subject.colorWheelView.layoutIfNeeded()
|
||||||
|
|
||||||
|
// Given
|
||||||
|
let touchLocation = CGPoint(x: -subject.handleSize.width / 2.0, y: subject.center.y)
|
||||||
|
|
||||||
|
// When
|
||||||
|
let hitView = subject.hitTest(touchLocation, with: UIEvent())
|
||||||
|
|
||||||
|
// Then
|
||||||
|
XCTAssertEqual(hitView, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHitTestShouldReturnNilWhenTouchIsOutsideHitbox() {
|
||||||
|
subject.colorWheelView.layoutIfNeeded()
|
||||||
|
|
||||||
|
// Given
|
||||||
|
let extendedSize: CGFloat = 12
|
||||||
|
subject.handleSize = CGSize(width: extendedSize, height: extendedSize)
|
||||||
|
let fakeHandle = makeFakeHandle()
|
||||||
|
let touchLocation = CGPoint(x: -extendedSize - 1, y: subject.center.y)
|
||||||
|
setCurrentHandle(to: fakeHandle)
|
||||||
|
|
||||||
|
// When
|
||||||
|
let hitView = subject.hitTest(touchLocation, with: UIEvent())
|
||||||
|
|
||||||
|
// Then
|
||||||
|
XCTAssertEqual(hitView, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
61
Tests/Extensions/UIColor+UtilsTests.swift
Normal file
61
Tests/Extensions/UIColor+UtilsTests.swift
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// UIColor+UtilsTests.swift
|
||||||
|
// ChromaColorPicker
|
||||||
|
//
|
||||||
|
// Created by Jonathan Cardasis on 11/8/19.
|
||||||
|
// Copyright © 2019 Jonathan Cardasis. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import ChromaColorPicker
|
||||||
|
|
||||||
|
class UIColor_UtilsTests: XCTestCase {
|
||||||
|
|
||||||
|
func testLightnessReturns1ForWhite() {
|
||||||
|
XCTAssertEqual(UIColor.white.lightness, 1.0, accuracy: 0.001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLightnessReturns0ForBlack() {
|
||||||
|
XCTAssertEqual(UIColor.black.lightness, 0.0, accuracy: 0.001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLightnessReturnsCorrectLightnessForYellow() {
|
||||||
|
XCTAssertEqual(UIColor.yellow.lightness, 0.886, accuracy: 0.001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLightnessReturnsCorrectLightnessForBlue() {
|
||||||
|
XCTAssertEqual(UIColor.blue.lightness, 0.114, accuracy: 0.001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBlueIsNotLight() {
|
||||||
|
XCTAssertFalse(UIColor.blue.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRedIsNotLight() {
|
||||||
|
XCTAssertFalse(UIColor.red.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPurpleIsNotLight() {
|
||||||
|
XCTAssertFalse(UIColor.purple.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tesBlackIsNotLight() {
|
||||||
|
XCTAssertFalse(UIColor.black.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testWhiteIsLight() {
|
||||||
|
XCTAssertTrue(UIColor.white.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGreenIsLight() {
|
||||||
|
XCTAssertTrue(UIColor.green.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOrangeIsLight() {
|
||||||
|
XCTAssertTrue(UIColor.orange.isLight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testYellowIsLight() {
|
||||||
|
XCTAssertTrue(UIColor.yellow.isLight)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user