8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | public class EFRGBView: UIView, EFColorView {
30 |
31 | let EFColorSampleViewHeight: CGFloat = 30.0
32 | let EFViewMargin: CGFloat = 20.0
33 | let EFSliderViewMargin: CGFloat = 30.0
34 | let EFRGBColorComponentsSize: Int = 3
35 |
36 | private let colorSample: UIView = {
37 | let view = UIView()
38 | view.accessibilityLabel = "color_sample"
39 | view.layer.borderColor = UIColor.black.cgColor
40 | view.layer.borderWidth = 0.5
41 | view.translatesAutoresizingMaskIntoConstraints = false
42 | return view
43 | }()
44 | var colorComponentViews: [EFColorComponentView] = []
45 | private var colorComponents = RGB(1, 1, 1, 1)
46 |
47 | weak public var delegate: EFColorViewDelegate?
48 |
49 | public var isTouched: Bool {
50 | return colorComponentViews.filter { $0.isTouched }.count > 0
51 | }
52 |
53 | public var color: UIColor {
54 | get {
55 | return UIColor(
56 | red: colorComponents.red,
57 | green: colorComponents.green,
58 | blue: colorComponents.blue,
59 | alpha: colorComponents.alpha
60 | )
61 | }
62 | set {
63 | colorComponents = EFRGBColorComponents(color: newValue)
64 | reloadData()
65 | }
66 | }
67 |
68 | override init(frame: CGRect) {
69 | super.init(frame: frame)
70 | ef_baseInit()
71 | }
72 |
73 | required public init?(coder aDecoder: NSCoder) {
74 | super.init(coder: aDecoder)
75 | ef_baseInit()
76 | }
77 |
78 | func reloadData() {
79 | colorSample.backgroundColor = color
80 | colorSample.accessibilityValue = EFHexStringFromColor(color: self.color)
81 | ef_reloadColorComponentViews(colorComponents: colorComponents)
82 | }
83 |
84 | // MARK: - Private methods
85 | private func ef_baseInit() {
86 | accessibilityLabel = "rgb_view"
87 | addSubview(colorSample)
88 |
89 | var tmp: [EFColorComponentView] = []
90 | let titles = [
91 | NSLocalizedString("Red", comment: ""),
92 | NSLocalizedString("Green", comment: ""),
93 | NSLocalizedString("Blue", comment: "")
94 | ]
95 | let maxValues = [
96 | EFRGBColorComponentMaxValue, EFRGBColorComponentMaxValue, EFRGBColorComponentMaxValue
97 | ]
98 | for i in 0 ..< EFRGBColorComponentsSize {
99 | let colorComponentView = ef_colorComponentViewWithTitle(
100 | title: titles[i], tag: i, maxValue: maxValues[i]
101 | )
102 | addSubview(colorComponentView)
103 | colorComponentView.addTarget(
104 | self, action: #selector(ef_colorComponentDidChangeValue(_:)), for: UIControl.Event.valueChanged
105 | )
106 | tmp.append(colorComponentView)
107 | }
108 |
109 | colorComponentViews = tmp
110 | ef_installConstraints()
111 | }
112 |
113 | @objc @IBAction private func ef_colorComponentDidChangeValue(_ sender: EFColorComponentView) {
114 | self.ef_setColorComponentValue(value: sender.value / sender.maximumValue, atIndex: UInt(sender.tag))
115 | self.delegate?.colorView(self, didChangeColor: self.color)
116 | self.reloadData()
117 | }
118 |
119 | private func ef_setColorComponentValue(value: CGFloat, atIndex index: UInt) {
120 | switch index {
121 | case 0:
122 | colorComponents.red = value
123 | case 1:
124 | colorComponents.green = value
125 | case 2:
126 | colorComponents.blue = value
127 | default:
128 | colorComponents.alpha = value
129 | }
130 | }
131 |
132 | private func ef_colorComponentViewWithTitle(title: String, tag: Int, maxValue: CGFloat) -> EFColorComponentView {
133 | let colorComponentView = EFColorComponentView()
134 | colorComponentView.title = title
135 | colorComponentView.translatesAutoresizingMaskIntoConstraints = false
136 | colorComponentView.tag = tag
137 | colorComponentView.maximumValue = maxValue
138 | return colorComponentView
139 | }
140 |
141 | private func ef_installConstraints() {
142 | let metrics = [
143 | "margin": EFViewMargin,
144 | "height": EFColorSampleViewHeight,
145 | "slider_margin": EFSliderViewMargin
146 | ]
147 | var views = [
148 | "colorSample": colorSample
149 | ]
150 |
151 | let visualFormats = [
152 | "H:|-margin-[colorSample]-margin-|",
153 | "V:|-margin-[colorSample(height)]"
154 | ]
155 | for visualFormat in visualFormats {
156 | addConstraints(
157 | NSLayoutConstraint.constraints(
158 | withVisualFormat: visualFormat,
159 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
160 | metrics: metrics,
161 | views: views
162 | )
163 | )
164 | }
165 |
166 | var previousView = colorSample
167 | for colorComponentView in colorComponentViews {
168 | views = [
169 | "previousView": previousView,
170 | "colorComponentView": colorComponentView
171 | ]
172 |
173 | let visualFormats = [
174 | "H:|-margin-[colorComponentView]-margin-|",
175 | "V:[previousView]-slider_margin-[colorComponentView]"
176 | ]
177 | for visualFormat in visualFormats {
178 | self.addConstraints(
179 | NSLayoutConstraint.constraints(
180 | withVisualFormat: visualFormat,
181 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
182 | metrics: metrics,
183 | views: views
184 | )
185 | )
186 | }
187 |
188 | previousView = colorComponentView
189 | }
190 |
191 | views = [
192 | "previousView": previousView
193 | ]
194 | addConstraints(
195 | NSLayoutConstraint.constraints(
196 | withVisualFormat: "V:[previousView]-(>=margin)-|",
197 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
198 | metrics: metrics,
199 | views: views
200 | )
201 | )
202 | }
203 |
204 | private func ef_colorComponentsWithRGB(rgb: RGB) -> [CGFloat] {
205 | return [rgb.red, rgb.green, rgb.blue, rgb.alpha]
206 | }
207 |
208 | private func ef_reloadColorComponentViews(colorComponents: RGB) {
209 | let components = ef_colorComponentsWithRGB(rgb: colorComponents)
210 |
211 | for (idx, colorComponentView) in colorComponentViews.enumerated() {
212 | let cgColors = self.ef_colorsWithColorComponents(colorComponents: components, currentColorIndex: colorComponentView.tag)
213 | let colors = cgColors.map { UIColor(cgColor: $0) }
214 |
215 | colorComponentView.setColors(colors: colors)
216 | colorComponentView.value = components[idx] * colorComponentView.maximumValue
217 | }
218 | }
219 |
220 | private func ef_colorsWithColorComponents(colorComponents: [CGFloat], currentColorIndex colorIndex: Int) -> [CGColor] {
221 | let currentColorValue = colorComponents[colorIndex]
222 | var colors = [CGFloat](repeating: 0, count: 12)
223 | for i in 0 ..< EFRGBColorComponentsSize {
224 | colors[i] = colorComponents[i]
225 | colors[i + 4] = colorComponents[i]
226 | colors[i + 8] = colorComponents[i]
227 | }
228 | colors[colorIndex] = 0
229 | colors[colorIndex + 4] = currentColorValue
230 | colors[colorIndex + 8] = 1.0
231 |
232 | let start = UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1)
233 | let middle = UIColor(red: colors[4], green: colors[5], blue: colors[6], alpha: 1)
234 | let end = UIColor(red: colors[8], green: colors[9], blue: colors[10], alpha: 1)
235 |
236 | return [start.cgColor, middle.cgColor, end.cgColor]
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DEPRECATED, use [UIColorPickerViewController](https://developer.apple.com/documentation/uikit/uicolorpickerviewcontroller) / [ColorPicker](https://developer.apple.com/documentation/swiftui/colorpicker) instead.
2 |
3 | ---
4 |
5 | 
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | EFColorPicker is a lightweight color picker in Swift, inspired by [MSColorPicker](https://github.com/sgl0v/MSColorPicker).
39 |
40 | > [中文介绍](https://github.com/EFPrefix/EFColorPicker/blob/master/README_CN.md)
41 |
42 | ## Overview
43 |
44 | Color picker component for iOS. It allows the user to select a color with color components. Key features:
45 |
46 | - iPhone & iPad support
47 | - Adaptive User Interface
48 | - Supports RGB and HSB color models
49 | - Well-documented
50 | - Compatible with iOS 8.0 (iPhone & iPad) and higher
51 |
52 | ## Preview
53 |
54 | | iPhone | | iPad |
55 | |:---------------------:|:---------------------:|:---------------------:|
56 | ||
57 |
58 | ## Example
59 |
60 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
61 |
62 | Then build and run `EFColorPicker.xcworkspace` in Xcode, the demo shows how to use and integrate the EFColorPicker into your project.
63 |
64 | ## Requirements
65 |
66 | | Version | Needs |
67 | |:-------|:-----------------------------------------------|
68 | | <5.0 | Xcode 10.0+
Swift 4.2+
iOS 8.0+ |
69 | | 5.x | Xcode 10.2+
Swift 5.0+
iOS 8.0+ |
70 |
71 | ## Installation
72 |
73 | ### CocoaPods
74 |
75 | EFColorPicker is available through [CocoaPods](http://cocoapods.org). To install
76 | it, simply add the following line to your Podfile:
77 |
78 | ```ruby
79 | pod 'EFColorPicker'
80 | ```
81 | ### Carthage
82 |
83 | You can use [Carthage](https://github.com/Carthage/Carthage) to install `EFColorPicker` by adding that to your Cartfile:
84 |
85 | ``` Swift
86 | github "EFPrefix/EFColorPicker"
87 | ```
88 |
89 | ### Swift Package Manager
90 |
91 | The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the Swift compiler.
92 |
93 | Once you have your Swift package set up, adding EFColorPicker as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
94 |
95 | ```swift
96 | dependencies: [
97 | .package(url: "https://github.com/EFPrefix/EFColorPicker.git", .upToNextMinor(from: "5.2.2"))
98 | ]
99 | ```
100 |
101 | ## Use
102 |
103 | 1. First, include EFColorPicker in your project:
104 |
105 | ```swift
106 | import EFColorPicker
107 | ```
108 |
109 | 2. Next, we can call EFColorPicker with pure code:
110 |
111 | ```swift
112 | let colorSelectionController = EFColorSelectionViewController()
113 | let navCtrl = UINavigationController(rootViewController: colorSelectionController)
114 | navCtrl.navigationBar.backgroundColor = UIColor.white
115 | navCtrl.navigationBar.isTranslucent = false
116 | navCtrl.modalPresentationStyle = UIModalPresentationStyle.popover
117 | navCtrl.popoverPresentationController?.delegate = self
118 | navCtrl.popoverPresentationController?.sourceView = sender
119 | navCtrl.popoverPresentationController?.sourceRect = sender.bounds
120 | navCtrl.preferredContentSize = colorSelectionController.view.systemLayoutSizeFitting(
121 | UILayoutFittingCompressedSize
122 | )
123 |
124 | colorSelectionController.delegate = self
125 | colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
126 | colorSelectionController.setMode(mode: EFColorSelectionMode.all)
127 |
128 | if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
129 | let doneBtn: UIBarButtonItem = UIBarButtonItem(
130 | title: NSLocalizedString("Done", comment: ""),
131 | style: UIBarButtonItemStyle.done,
132 | target: self,
133 | action: #selector(ef_dismissViewController(sender:))
134 | )
135 | colorSelectionController.navigationItem.rightBarButtonItem = doneBtn
136 | }
137 | self.present(navCtrl, animated: true, completion: nil)
138 | ```
139 |
140 | Also we can use EFColorPicker in Storyboard:
141 |
142 | ```swift
143 | if "showPopover" == segue.identifier {
144 | guard let destNav: UINavigationController = segue.destination as? UINavigationController else {
145 | return
146 | }
147 | if let size = destNav.visibleViewController?.view.systemLayoutSizeFitting(UILayoutFittingCompressedSize) {
148 | destNav.preferredContentSize = size
149 | }
150 | destNav.popoverPresentationController?.delegate = self
151 | if let colorSelectionController = destNav.visibleViewController as? EFColorSelectionViewController {
152 | colorSelectionController.delegate = self
153 | colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
154 |
155 | if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
156 | let doneBtn: UIBarButtonItem = UIBarButtonItem(
157 | title: NSLocalizedString("Done", comment: ""),
158 | style: UIBarButtonItemStyle.done,
159 | target: self,
160 | action: #selector(ef_dismissViewController(sender:))
161 | )
162 | colorSelectionController.navigationItem.rightBarButtonItem = doneBtn
163 | }
164 | }
165 | }
166 | ```
167 |
168 | You can control the visibility of color textField by change the `isColorTextFieldHidden` property of `EFColorSelectionViewController`, for example:
169 |
170 | | isColorTextFieldHidden: true | | isColorTextFieldHidden: false | |
171 | |:---------------------:|:---------------------:|:---------------------:|:---------------------:|
172 | |||
173 |
174 | For more detail, please see the demo.
175 |
176 | 3. Last but not the least, you should implement `EFColorSelectionViewControllerDelegate` so you can sense the color changes:
177 |
178 | ```swift
179 | // MARK:- EFColorSelectionViewControllerDelegate
180 | func colorViewController(colorViewCntroller: EFColorSelectionViewController, didChangeColor color: UIColor) {
181 | self.view.backgroundColor = color
182 |
183 | // TODO: You can do something here when color changed.
184 | print("New color: " + color.debugDescription)
185 | }
186 | ```
187 |
188 | ## Apps using EFColorPicker
189 |
190 |
209 |
210 | ## Author
211 |
212 | EyreFree, eyrefree@eyrefree.org
213 |
214 | ## License
215 |
216 | 
217 |
218 | EFColorPicker is available under the MIT license. See the LICENSE file for more info.
219 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | 已归档,建议使用 [UIColorPickerViewController](https://developer.apple.com/documentation/uikit/uicolorpickerviewcontroller) / [ColorPicker](https://developer.apple.com/documentation/swiftui/colorpicker) 替代。
2 |
3 | ---
4 |
5 | 
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | EFColorPicker 是一个纯 Swift 的轻量级 iOS 颜色选择器,受 [MSColorPicker](https://github.com/sgl0v/MSColorPicker) 启发。
42 |
43 | > [English Introduction](https://github.com/EFPrefix/EFColorPicker/blob/master/README.md)
44 |
45 | ## 概述
46 |
47 | iOS 颜色选择器组件,它能够让用户选择自定义颜色,关键特性如下:
48 |
49 | - 支持 iPhone 和 iPad
50 | - 自适应的用户界面
51 | - 支持 RGB 和 HSB 两种颜色模式
52 | - 比较完善的文档和注释
53 | - 支持 iOS 8.0 (iPhone & iPad) 及更高版本
54 |
55 | ## 预览
56 |
57 | | iPhone | | iPad |
58 | |:---------------------:|:---------------------:|:---------------------:|
59 | ||
60 |
61 | ## 示例
62 |
63 | 1. 利用 `git clone` 命令下载本仓库;
64 | 2. 利用 cd 命令切换到 Example 目录下,执行 `pod install` 命令;
65 | 3. 随后打开 `EFColorPicker.xcworkspace` 编译即可。
66 |
67 | 或执行以下命令:
68 |
69 | ```bash
70 | git clone git@github.com:EFPrefix/EFColorPicker.git; cd EFColorPicker/Example; pod install; open EFColorPicker.xcworkspace
71 | ```
72 |
73 | ## 环境
74 |
75 | | 版本 | 需求 |
76 | |:-------|:-----------------------------------------------|
77 | | <5.0 | Xcode 10.0+
Swift 4.2+
iOS 8.0+ |
78 | | 5.x | Xcode 10.2+
Swift 5.0+
iOS 8.0+ |
79 |
80 | ## 安装
81 |
82 | ### CocoaPods
83 |
84 | EFColorPicker 可以通过 [CocoaPods](http://cocoapods.org) 进行获取。只需要在你的 Podfile 中添加如下代码就能实现引入:
85 |
86 | ```
87 | pod "EFColorPicker"
88 | ```
89 |
90 | ### Swift Package Manager
91 |
92 | [Swift Package Manager](https://swift.org/package-manager/) 是一个集成在 Swift 编译器中的用来进行 Swift 代码自动化发布的工具。
93 |
94 | 如果你已经建立了你的 Swift 包,将 EFColorPicker 加入依赖是十分容易的,只需要将其添加到你的 `Package.swift` 文件的 `dependencies` 项中即可:
95 |
96 | ```swift
97 | dependencies: [
98 | .package(url: "https://github.com/EFPrefix/EFColorPicker.git", .upToNextMinor(from: "5.2.2"))
99 | ]
100 | ```
101 |
102 | ## 使用
103 |
104 | 1. 首先,需要导入 EFColorPicker 库:
105 |
106 | ```swift
107 | import EFColorPicker
108 | ```
109 |
110 | 2. 接下来,可以通过纯代码调用:
111 |
112 | ```swift
113 | let colorSelectionController = EFColorSelectionViewController()
114 | let navCtrl = UINavigationController(rootViewController: colorSelectionController)
115 | navCtrl.navigationBar.backgroundColor = UIColor.white
116 | navCtrl.navigationBar.isTranslucent = false
117 | navCtrl.modalPresentationStyle = UIModalPresentationStyle.popover
118 | navCtrl.popoverPresentationController?.delegate = self
119 | navCtrl.popoverPresentationController?.sourceView = sender
120 | navCtrl.popoverPresentationController?.sourceRect = sender.bounds
121 | navCtrl.preferredContentSize = colorSelectionController.view.systemLayoutSizeFitting(
122 | UILayoutFittingCompressedSize
123 | )
124 |
125 | colorSelectionController.delegate = self
126 | colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
127 | colorSelectionController.setMode(mode: EFColorSelectionMode.all)
128 |
129 | if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
130 | let doneBtn: UIBarButtonItem = UIBarButtonItem(
131 | title: NSLocalizedString("Done", comment: ""),
132 | style: UIBarButtonItemStyle.done,
133 | target: self,
134 | action: #selector(ef_dismissViewController(sender:))
135 | )
136 | colorSelectionController.navigationItem.rightBarButtonItem = doneBtn
137 | }
138 | self.present(navCtrl, animated: true, completion: nil)
139 | ```
140 |
141 | 也可以通过 Storyboard 调用:
142 |
143 | ```swift
144 | if "showPopover" == segue.identifier {
145 | guard let destNav: UINavigationController = segue.destination as? UINavigationController else {
146 | return
147 | }
148 | if let size = destNav.visibleViewController?.view.systemLayoutSizeFitting(UILayoutFittingCompressedSize) {
149 | destNav.preferredContentSize = size
150 | }
151 | destNav.popoverPresentationController?.delegate = self
152 | if let colorSelectionController = destNav.visibleViewController as? EFColorSelectionViewController {
153 | colorSelectionController.delegate = self
154 | colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
155 |
156 | if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
157 | let doneBtn: UIBarButtonItem = UIBarButtonItem(
158 | title: NSLocalizedString("Done", comment: ""),
159 | style: UIBarButtonItemStyle.done,
160 | target: self,
161 | action: #selector(ef_dismissViewController(sender:))
162 | )
163 | colorSelectionController.navigationItem.rightBarButtonItem = doneBtn
164 | }
165 | }
166 | }
167 | ```
168 |
169 | 你可以通过修改 `EFColorSelectionViewController` 的 `isColorTextFieldHidden` 属性来控制颜色编辑框的可见性,效果如下:
170 |
171 | | isColorTextFieldHidden: true | | isColorTextFieldHidden: false | |
172 | |:---------------------:|:---------------------:|:---------------------:|:---------------------:|
173 | |||
174 |
175 | 具体可参考示例程序。
176 |
177 | 3. 最后,不要忘记调用的 ViewController 需要继承 EFColorSelectionViewControllerDelegate 来及时获取颜色的变化:
178 |
179 | ```swift
180 | // MARK:- EFColorSelectionViewControllerDelegate
181 | func colorViewController(colorViewCntroller: EFColorSelectionViewController, didChangeColor color: UIColor) {
182 | self.view.backgroundColor = color
183 |
184 | // TODO: You can do something here when color changed.
185 | print("New color: " + color.debugDescription)
186 | }
187 | ```
188 |
189 | ## 使用 EFColorPicker 的应用
190 |
191 |
210 |
211 | ## 作者
212 |
213 | EyreFree, eyrefree@eyrefree.org
214 |
215 | ## 协议
216 |
217 | 
218 |
219 | EFColorPicker 基于 MIT 协议进行分发和使用,更多信息参见协议文件。
220 |
--------------------------------------------------------------------------------
/EFColorPicker/Classes/EFHSBView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EFHSBView.swift
3 | // EFColorPicker
4 | //
5 | // Created by EyreFree on 2017/9/29.
6 | //
7 | // Copyright (c) 2017 EyreFree
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | // The view to edit HSB color components.
30 | public class EFHSBView: UIView, EFColorView, UITextFieldDelegate {
31 |
32 | let EFColorSampleViewHeight: CGFloat = 30.0
33 | let EFViewMargin: CGFloat = 20.0
34 | let EFColorWheelDimension: CGFloat = 200.0
35 |
36 | private let colorWheel = EFColorWheelView()
37 | public let brightnessView: EFColorComponentView = {
38 | let view = EFColorComponentView()
39 | view.title = NSLocalizedString("Brightness", comment: "")
40 | view.maximumValue = EFHSBColorComponentMaxValue
41 | view.format = "%.2f"
42 | view.translatesAutoresizingMaskIntoConstraints = false
43 | view.setColors(colors: [.black, .white])
44 | return view
45 | }()
46 | private let colorSample: UIView = {
47 | let view = UIView()
48 | view.accessibilityLabel = "color_sample"
49 | view.layer.borderColor = UIColor.black.cgColor
50 | view.layer.borderWidth = 0.5
51 | view.translatesAutoresizingMaskIntoConstraints = false
52 | return view
53 | }()
54 | private var colorComponents = HSB(1, 1, 1, 1)
55 | private var layoutConstraints: [NSLayoutConstraint] = []
56 |
57 | weak public var delegate: EFColorViewDelegate?
58 |
59 | public var isTouched: Bool {
60 | if self.colorWheel.isTouched {
61 | return true
62 | }
63 | if self.brightnessView.isTouched {
64 | return true
65 | }
66 | return false
67 | }
68 |
69 | public var color: UIColor {
70 | get {
71 | return UIColor(
72 | hue: colorComponents.hue,
73 | saturation: colorComponents.saturation,
74 | brightness: colorComponents.brightness,
75 | alpha: colorComponents.alpha
76 | )
77 | }
78 | set {
79 | colorComponents = EFRGB2HSB(rgb: EFRGBColorComponents(color: newValue))
80 | self.reloadData()
81 | }
82 | }
83 |
84 | override init(frame: CGRect) {
85 | super.init(frame: frame)
86 | self.ef_baseInit()
87 | }
88 |
89 | required public init?(coder aDecoder: NSCoder) {
90 | super.init(coder: aDecoder)
91 | self.ef_baseInit()
92 | }
93 |
94 | func reloadData() {
95 | colorSample.backgroundColor = color
96 | colorSample.accessibilityValue = EFHexStringFromColor(color: color)
97 | self.ef_reloadViewsWithColorComponents(colorComponents: colorComponents)
98 | self.colorWheel.display(colorWheel.layer)
99 | }
100 | override public func updateConstraints() {
101 | self.ef_updateConstraints()
102 | super.updateConstraints()
103 | }
104 |
105 | // MARK: - Private methods
106 | private func ef_baseInit() {
107 | accessibilityLabel = "hsb_view"
108 | addSubview(colorSample)
109 |
110 | colorWheel.translatesAutoresizingMaskIntoConstraints = false
111 | addSubview(colorWheel)
112 | addSubview(brightnessView)
113 |
114 | colorWheel.addTarget(
115 | self, action: #selector(ef_colorDidChangeValue(sender:)), for: UIControl.Event.valueChanged
116 | )
117 | brightnessView.addTarget(
118 | self, action: #selector(ef_brightnessDidChangeValue(sender:)), for: UIControl.Event.valueChanged
119 | )
120 | setNeedsUpdateConstraints()
121 | }
122 |
123 | private func ef_updateConstraints() {
124 | // remove all constraints first
125 | if !layoutConstraints.isEmpty {
126 | removeConstraints(layoutConstraints)
127 | }
128 |
129 | layoutConstraints = UIUserInterfaceSizeClass.compact == traitCollection.verticalSizeClass
130 | ? ef_constraintsForCompactVerticalSizeClass()
131 | : ef_constraintsForRegularVerticalSizeClass()
132 | addConstraints(layoutConstraints)
133 | }
134 |
135 | private func ef_constraintsForRegularVerticalSizeClass() -> [NSLayoutConstraint] {
136 | let metrics = [
137 | "margin": EFViewMargin,
138 | "height": EFColorSampleViewHeight,
139 | "color_wheel_dimension": EFColorWheelDimension
140 | ]
141 | let views = [
142 | "colorSample": colorSample,
143 | "colorWheel": colorWheel,
144 | "brightnessView": brightnessView
145 | ]
146 |
147 | var layoutConstraints: [NSLayoutConstraint] = []
148 | let visualFormats = [
149 | "H:|-margin-[colorSample]-margin-|",
150 | "H:|-margin-[colorWheel(>=color_wheel_dimension)]-margin-|",
151 | "H:|-margin-[brightnessView]-margin-|",
152 | "V:|-margin-[colorSample(height)]-margin-[colorWheel]-margin-[brightnessView]-(>=margin@250)-|"
153 | ]
154 | for visualFormat in visualFormats {
155 | layoutConstraints.append(
156 | contentsOf: NSLayoutConstraint.constraints(
157 | withVisualFormat: visualFormat,
158 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
159 | metrics: metrics,
160 | views: views
161 | )
162 | )
163 | }
164 | layoutConstraints.append(
165 | NSLayoutConstraint(
166 | item: colorWheel,
167 | attribute: .width,
168 | relatedBy: .equal,
169 | toItem: colorWheel,
170 | attribute: .height,
171 | multiplier: 1,
172 | constant: 0)
173 | )
174 | return layoutConstraints
175 | }
176 | private func ef_constraintsForCompactVerticalSizeClass() -> [NSLayoutConstraint] {
177 | let metrics = [
178 | "margin": EFViewMargin,
179 | "height": EFColorSampleViewHeight,
180 | "color_wheel_dimension": EFColorWheelDimension
181 | ]
182 | let views = [
183 | "colorSample": colorSample,
184 | "colorWheel": colorWheel,
185 | "brightnessView": brightnessView
186 | ]
187 |
188 | var layoutConstraints: [NSLayoutConstraint] = []
189 | let visualFormats = [
190 | "H:|-margin-[colorSample]-margin-|",
191 | "H:|-margin-[colorWheel(>=color_wheel_dimension)]-margin-[brightnessView]-(margin@500)-|",
192 | "V:|-margin-[colorSample(height)]-margin-[colorWheel]-(margin@500)-|"
193 | ]
194 | for visualFormat in visualFormats {
195 | layoutConstraints.append(
196 | contentsOf: NSLayoutConstraint.constraints(
197 | withVisualFormat: visualFormat,
198 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
199 | metrics: metrics,
200 | views: views
201 | )
202 | )
203 | }
204 | layoutConstraints.append(
205 | NSLayoutConstraint(
206 | item: colorWheel,
207 | attribute: .width,
208 | relatedBy: .equal,
209 | toItem: colorWheel,
210 | attribute: .height,
211 | multiplier: 1,
212 | constant: 0)
213 | )
214 | layoutConstraints.append(
215 | NSLayoutConstraint(
216 | item: brightnessView,
217 | attribute: .centerY,
218 | relatedBy: .equal,
219 | toItem: self,
220 | attribute: .centerY,
221 | multiplier: 1,
222 | constant: 0)
223 | )
224 | return layoutConstraints
225 | }
226 |
227 | private func ef_reloadViewsWithColorComponents(colorComponents: HSB) {
228 | colorWheel.hue = colorComponents.hue
229 | colorWheel.saturation = colorComponents.saturation
230 | colorWheel.brightness = colorComponents.brightness
231 | self.ef_updateSlidersWithColorComponents(colorComponents: colorComponents)
232 | }
233 |
234 | private func ef_updateSlidersWithColorComponents(colorComponents: HSB) {
235 | brightnessView.value = colorComponents.brightness
236 | }
237 |
238 | @objc private func ef_colorDidChangeValue(sender: EFColorWheelView) {
239 | colorComponents.hue = sender.hue
240 | colorComponents.saturation = sender.saturation
241 | self.delegate?.colorView(self, didChangeColor: self.color)
242 | self.reloadData()
243 | }
244 |
245 | @objc private func ef_brightnessDidChangeValue(sender: EFColorComponentView) {
246 | colorComponents.brightness = sender.value
247 | self.colorWheel.brightness = sender.value
248 | self.delegate?.colorView(self, didChangeColor: self.color)
249 | self.reloadData()
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/Example/EFColorPicker/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
71 |
83 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/EFColorPicker/Classes/EFColorWheelView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EFColorWheelView.swift
3 | // EFColorPicker
4 | //
5 | // Created by EyreFree on 2017/9/29.
6 | //
7 | // Copyright (c) 2017 EyreFree
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 | import CoreGraphics
29 |
30 | // The color wheel view.
31 | public class EFColorWheelView: UIControl {
32 |
33 | public var isTouched = false
34 | var wheelImage: CGImage?
35 |
36 | // The hue value.
37 | public var hue: CGFloat = 0.0 {
38 | didSet {
39 | setSelectedPoint(point: ef_selectedPoint())
40 | setNeedsDisplay()
41 | }
42 | }
43 |
44 | // The saturation value.
45 | public var saturation: CGFloat = 0.0 {
46 | didSet {
47 | setSelectedPoint(point: ef_selectedPoint())
48 | setNeedsDisplay()
49 | }
50 | }
51 |
52 | // The saturation value.
53 | public var brightness: CGFloat = 1.0 {
54 | didSet {
55 | self.setSelectedPoint(point: ef_selectedPoint())
56 | if oldValue != brightness {
57 | drawWheelImage()
58 | }
59 | }
60 | }
61 |
62 | private lazy var indicatorLayer: CALayer = {
63 | let dimension: CGFloat = 33
64 | let edgeColor = UIColor(white: 0.9, alpha: 0.8)
65 |
66 | let indicatorLayer = CALayer()
67 | indicatorLayer.cornerRadius = dimension / 2
68 | indicatorLayer.borderColor = edgeColor.cgColor
69 | indicatorLayer.borderWidth = 2
70 | indicatorLayer.backgroundColor = UIColor.white.cgColor
71 | indicatorLayer.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
72 | indicatorLayer.position = CGPoint(x: self.bounds.width / 2, y: self.bounds.height / 2)
73 | indicatorLayer.shadowColor = UIColor.black.cgColor
74 | indicatorLayer.shadowOffset = CGSize.zero
75 | indicatorLayer.shadowRadius = 1
76 | indicatorLayer.shadowOpacity = 0.5
77 | return indicatorLayer
78 | }()
79 |
80 | override open class var requiresConstraintBasedLayout: Bool {
81 | return true
82 | }
83 |
84 | override init(frame: CGRect) {
85 | super.init(frame: frame)
86 |
87 | accessibilityLabel = "color_wheel_view"
88 | layer.delegate = self
89 | layer.addSublayer(indicatorLayer)
90 |
91 | // [self setSelectedPoint:CGPointMake(dimension / 2, dimension / 2)];
92 | }
93 |
94 | required public init?(coder aDecoder: NSCoder) {
95 | fatalError("init(coder:) has not been implemented")
96 | }
97 |
98 | override public func touchesBegan(_ touches: Set, with event: UIEvent?) {
99 | isTouched = true
100 | if let position = touches.first?.location(in: self) {
101 | onTouchEventWithPosition(point: position)
102 | }
103 | }
104 |
105 | override public func touchesMoved(_ touches: Set, with event: UIEvent?) {
106 | if let position = touches.first?.location(in: self) {
107 | onTouchEventWithPosition(point: position)
108 | }
109 | }
110 |
111 | override public func touchesEnded(_ touches: Set, with event: UIEvent?) {
112 | isTouched = false
113 | if let position = touches.first?.location(in: self) {
114 | onTouchEventWithPosition(point: position)
115 | }
116 | }
117 |
118 | func onTouchEventWithPosition(point: CGPoint) {
119 | let radius = self.bounds.width / 2
120 |
121 | let mx = Double(radius - point.x)
122 | let my = Double(radius - point.y)
123 | let dist = CGFloat(sqrt(mx * mx + my * my))
124 |
125 | if dist <= radius {
126 | var h = hue
127 | var s = saturation
128 | ef_colorWheelValueWithPosition(position: point, hue: &h, saturation: &s)
129 | hue = h
130 | saturation = s
131 | setSelectedPoint(point: point)
132 | sendActions(for: .valueChanged)
133 | }
134 | }
135 |
136 | func setSelectedPoint(point: CGPoint) {
137 | let selectedColor = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1)
138 |
139 | CATransaction.begin()
140 | CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
141 | self.indicatorLayer.position = point
142 | self.indicatorLayer.backgroundColor = selectedColor.cgColor
143 | CATransaction.commit()
144 | }
145 |
146 | // MARK: - CALayerDelegate methods
147 | override public func display(_ layer: CALayer) {
148 | guard wheelImage == nil else { return }
149 | drawWheelImage()
150 | }
151 |
152 | override public func layoutSublayers(of layer: CALayer) {
153 | if layer == self.layer {
154 | self.setSelectedPoint(point: self.ef_selectedPoint())
155 | self.layer.setNeedsDisplay()
156 | }
157 | }
158 |
159 | // MARK: - Private methods
160 | private func drawWheelImage() {
161 | let dimension: CGFloat = min(self.frame.width, self.frame.height)
162 | guard let bitmapData = CFDataCreateMutable(nil, 0) else {
163 | return
164 | }
165 |
166 | CFDataSetLength(bitmapData, CFIndex(dimension * dimension * 4))
167 | self.ef_colorWheelBitmap(
168 | bitmap: CFDataGetMutableBytePtr(bitmapData),
169 | withSize: CGSize(width: dimension, height: dimension)
170 | )
171 | if let image = self.ef_imageWithRGBAData(data: bitmapData, width: Int(dimension), height: Int(dimension)) {
172 | wheelImage = image
173 | self.layer.contents = wheelImage
174 | }
175 | }
176 |
177 | private func ef_selectedPoint() -> CGPoint {
178 | let dimension = min(frame.width, frame.height)
179 |
180 | let radius = saturation * dimension / 2
181 | let x = dimension / 2 + radius * CGFloat(cos(Double(hue) * Double.pi * 2.0))
182 | let y = dimension / 2 + radius * CGFloat(sin(Double(hue) * Double.pi * 2.0))
183 |
184 | return CGPoint(x: x, y: y)
185 | }
186 |
187 | private func ef_colorWheelBitmap(bitmap: UnsafeMutablePointer?, withSize size: CGSize) {
188 | if size.width <= 0 || size.height <= 0 {
189 | return
190 | }
191 |
192 | for y in 0 ..< Int(size.width) {
193 | for x in 0 ..< Int(size.height) {
194 | var hue: CGFloat = 0, saturation: CGFloat = 0, a: CGFloat = 0.0
195 | var h = hue
196 | var s = saturation
197 | ef_colorWheelValueWithPosition(position: CGPoint(x: x, y: y), hue: &h, saturation: &s)
198 | hue = h
199 | saturation = s
200 |
201 | var rgb = RGB(1, 1, 1, 1)
202 | if saturation < 1.0 {
203 | // Antialias the edge of the circle.
204 | if saturation > 0.99 {
205 | a = (1.0 - saturation) * 100
206 | } else {
207 | a = 1.0
208 | }
209 |
210 | let hsb = HSB(hue, saturation, brightness, a)
211 | rgb = EFHSB2RGB(hsb: hsb)
212 | }
213 |
214 | let i = 4 * (x + y * Int(size.width))
215 | bitmap?[i] = UInt8(rgb.red * 0xff)
216 | bitmap?[i + 1] = UInt8(rgb.green * 0xff)
217 | bitmap?[i + 2] = UInt8(rgb.blue * 0xff)
218 | bitmap?[i + 3] = UInt8(rgb.alpha * 0xff)
219 | }
220 | }
221 | }
222 |
223 | private func ef_colorWheelValueWithPosition(position: CGPoint, hue: inout CGFloat, saturation: inout CGFloat) {
224 | let c = Int(bounds.width / 2)
225 | let dx = (position.x - CGFloat(c)) / CGFloat(c)
226 | let dy = (position.y - CGFloat(c)) / CGFloat(c)
227 | let d = CGFloat(sqrt(Double(dx * dx + dy * dy)))
228 |
229 | saturation = d
230 |
231 | if d == 0 {
232 | hue = 0
233 | } else {
234 | hue = acos(dx / d) / CGFloat.pi / 2.0
235 |
236 | if dy < 0 {
237 | hue = 1.0 - hue
238 | }
239 | }
240 | }
241 |
242 | private func ef_imageWithRGBAData(data: CFData, width: Int, height: Int) -> CGImage? {
243 | guard let dataProvider = CGDataProvider(data: data) else {
244 | return nil
245 | }
246 | let colorSpace = CGColorSpaceCreateDeviceRGB()
247 |
248 | let imageRef = CGImage(
249 | width: width,
250 | height: height,
251 | bitsPerComponent: 8,
252 | bitsPerPixel: 32,
253 | bytesPerRow: width * 4,
254 | space: colorSpace,
255 | bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue),
256 | provider: dataProvider,
257 | decode: nil,
258 | shouldInterpolate: false,
259 | intent: CGColorRenderingIntent.defaultIntent
260 | )
261 | return imageRef
262 | }
263 | }
264 |
265 | // MARK: - Fix iOS 13 popover style doesn't play well with the Color Wheel
266 | // https://github.com/EFPrefix/EFColorPicker/issues/25
267 | extension EFColorWheelView{
268 | override public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
269 | if gestureRecognizer is UIPanGestureRecognizer{
270 | if let hsbView = self.superview as? EFHSBView{
271 | return !hsbView.isTouched
272 | }
273 | }
274 | return true
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/EFColorPicker/Classes/EFColorComponentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EFColorComponentView.swift
3 | // EFColorPicker
4 | //
5 | // Created by EyreFree on 2017/9/28.
6 | //
7 | // Copyright (c) 2017 EyreFree
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | // The view to edit a color component.
30 | public class EFColorComponentView: UIControl {
31 |
32 | // Indicates if the user touches the control at the moment
33 | public var isTouched: Bool {
34 | return slider.isTouched
35 | }
36 |
37 | // Temporary disabled the color component editing via text field
38 | public var colorTextFieldEnabled = false {
39 | didSet {
40 | if textField.isHidden == colorTextFieldEnabled {
41 | ef_remakeConstraints()
42 | textField.isHidden = !colorTextFieldEnabled
43 | }
44 | }
45 | }
46 | let EFColorComponentViewSpacing: CGFloat = 5.0
47 | let EFColorComponentLabelWidth: CGFloat = 60.0
48 | let EFColorComponentTextFieldWidth: CGFloat = 50.0
49 |
50 | // The title.
51 | var title: String {
52 | get {
53 | return label.text ?? ""
54 | }
55 | set {
56 | label.text = newValue
57 | }
58 | }
59 |
60 | // The current value. The default value is 0.0.
61 | var value: CGFloat {
62 | get {
63 | return slider.value
64 | }
65 | set {
66 | slider.setValue(value: newValue)
67 | textField.text = String(format: format, value)
68 | }
69 | }
70 |
71 | // The minimum value. The default value is 0.0.
72 | var minimumValue: CGFloat {
73 | get {
74 | return slider.minimumValue
75 | }
76 | set {
77 | slider.minimumValue = newValue
78 | }
79 | }
80 |
81 | // The maximum value. The default value is 255.0.
82 | var maximumValue: CGFloat {
83 | get {
84 | return slider.maximumValue
85 | }
86 | set {
87 | slider.maximumValue = newValue
88 | }
89 | }
90 |
91 | // The format string to use apply for textfield value. \c %.f by default.
92 | var format: String = "%.f"
93 |
94 | private let label: UILabel = {
95 | let label = UILabel()
96 | label.translatesAutoresizingMaskIntoConstraints = false
97 | label.adjustsFontSizeToFitWidth = true
98 | return label
99 | }()
100 | private let slider = EFSliderView() // The color slider to edit color component.
101 | private lazy var textField: UITextField = {
102 | let text = UITextField()
103 | text.borderStyle = .roundedRect
104 | text.translatesAutoresizingMaskIntoConstraints = false
105 | text.keyboardType = .numbersAndPunctuation
106 | text.isHidden = !colorTextFieldEnabled
107 | text.delegate = self
108 | return text
109 | }()
110 |
111 | override open class var requiresConstraintBasedLayout: Bool {
112 | return true
113 | }
114 | override init(frame: CGRect) {
115 | super.init(frame: frame)
116 | ef_baseInit()
117 | }
118 |
119 | required public init?(coder aDecoder: NSCoder) {
120 | super.init(coder: aDecoder)
121 | ef_baseInit()
122 | }
123 |
124 | // Sets the array of CGColorRef objects defining the color of each gradient stop on a slider's track.
125 | // The location of each gradient stop is evaluated with formula: i * width_of_the_track / number_of_colors.
126 | // @param colors An array of CGColorRef objects.
127 | func setColors(colors: [UIColor]) {
128 | if colors.count <= 1 {
129 | fatalError("‘colors: [CGColor]’ at least need to have 2 elements")
130 | }
131 | slider.setColors(colors: colors)
132 | }
133 | // MARK: - Private methods
134 | private func ef_baseInit() {
135 | accessibilityLabel = "color_component_view"
136 | addSubview(label)
137 | slider.maximumValue = EFRGBColorComponentMaxValue
138 | slider.translatesAutoresizingMaskIntoConstraints = false
139 | slider.addTarget(self, action: #selector(ef_didChangeSliderValue(sender:)), for: .valueChanged)
140 | addSubview(slider)
141 | addSubview(textField)
142 | value = 0.0
143 | self.ef_installConstraints()
144 | }
145 |
146 | @objc private func ef_didChangeSliderValue(sender: EFSliderView) {
147 | value = sender.value
148 | sendActions(for: .valueChanged)
149 | }
150 |
151 | private func ef_installConstraints() {
152 | if colorTextFieldEnabled {
153 | let views: [String: Any] = [
154 | "label": label,
155 | "slider": slider,
156 | "textField": textField
157 | ]
158 | let metrics: [String: Any] = [
159 | "spacing": EFColorComponentViewSpacing,
160 | "label_width": EFColorComponentLabelWidth,
161 | "textfield_width": EFColorComponentTextFieldWidth
162 | ]
163 |
164 | addConstraints(
165 | NSLayoutConstraint.constraints(
166 | withVisualFormat: "H:|[label(label_width)]-spacing-[slider]-spacing-[textField(textfield_width)]|",
167 | options: .alignAllCenterY,
168 | metrics: metrics,
169 | views: views
170 | )
171 | )
172 | addConstraints(
173 | NSLayoutConstraint.constraints(
174 | withVisualFormat: "V:|[label]|",
175 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
176 | metrics: nil,
177 | views: views
178 | )
179 | )
180 | addConstraints(
181 | NSLayoutConstraint.constraints(
182 | withVisualFormat: "V:|[textField]|",
183 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
184 | metrics: nil,
185 | views: views
186 | )
187 | )
188 | } else {
189 | let views: [String: Any] = [
190 | "label": label,
191 | "slider": slider
192 | ]
193 | let metrics: [String: Any] = [
194 | "spacing": EFColorComponentViewSpacing,
195 | "label_width": EFColorComponentLabelWidth
196 | ]
197 | addConstraints(
198 | NSLayoutConstraint.constraints(
199 | withVisualFormat: "H:|[label(label_width)]-spacing-[slider]-spacing-|",
200 | options: .alignAllCenterY,
201 | metrics: metrics,
202 | views: views
203 | )
204 | )
205 | addConstraints(
206 | NSLayoutConstraint.constraints(
207 | withVisualFormat: "V:|[label]|",
208 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
209 | metrics: nil,
210 | views: views
211 | )
212 | )
213 | }
214 | }
215 |
216 | private func ef_remakeConstraints() {
217 | // Remove all old constraints
218 | if !colorTextFieldEnabled {
219 | let views: [String: Any] = [
220 | "label": label,
221 | "slider": slider,
222 | "textField": textField
223 | ]
224 | let metrics: [String: Any] = [
225 | "spacing": EFColorComponentViewSpacing,
226 | "label_width": EFColorComponentLabelWidth,
227 | "textfield_width": EFColorComponentTextFieldWidth
228 | ]
229 | removeConstraints(
230 | NSLayoutConstraint.constraints(
231 | withVisualFormat: "H:|[label(label_width)]-spacing-[slider]-spacing-[textField(textfield_width)]|",
232 | options: .alignAllCenterY,
233 | metrics: metrics,
234 | views: views
235 | )
236 | )
237 | removeConstraints(
238 | NSLayoutConstraint.constraints(
239 | withVisualFormat: "V:|[label]|",
240 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
241 | metrics: nil,
242 | views: views
243 | )
244 | )
245 | removeConstraints(
246 | NSLayoutConstraint.constraints(
247 | withVisualFormat: "V:|[textField]|",
248 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
249 | metrics: nil,
250 | views: views
251 | )
252 | )
253 | } else {
254 | let views: [String: Any] = [
255 | "label": label,
256 | "slider": slider
257 | ]
258 | let metrics: [String: Any] = [
259 | "spacing": EFColorComponentViewSpacing,
260 | "label_width": EFColorComponentLabelWidth
261 | ]
262 | removeConstraints(
263 | NSLayoutConstraint.constraints(
264 | withVisualFormat: "H:|[label(label_width)]-spacing-[slider]-spacing-|",
265 | options: NSLayoutConstraint.FormatOptions.alignAllCenterY,
266 | metrics: metrics,
267 | views: views
268 | )
269 | )
270 | removeConstraints(
271 | NSLayoutConstraint.constraints(
272 | withVisualFormat: "V:|[label]|",
273 | options: NSLayoutConstraint.FormatOptions(rawValue: 0),
274 | metrics: nil,
275 | views: views
276 | )
277 | )
278 | }
279 |
280 | // Readd control
281 | for control in [label, slider, textField] {
282 | control.removeFromSuperview()
283 | self.addSubview(control)
284 | }
285 |
286 | // Add new constraints
287 | ef_installConstraints()
288 | }
289 | }
290 | extension EFColorComponentView: UITextFieldDelegate {
291 | // MARK: - UITextFieldDelegate methods
292 | public func textFieldDidEndEditing(_ textField: UITextField) {
293 | self.value = CGFloat(Double(textField.text ?? "") ?? 0)
294 | self.sendActions(for: .valueChanged)
295 | }
296 |
297 | public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
298 | textField.resignFirstResponder()
299 | return true
300 | }
301 |
302 | public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
303 | let newString = NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)
304 | //first, check if the new string is numeric only. If not, return NO;
305 | let characterSet = NSCharacterSet(charactersIn: "0123456789,.").inverted
306 | if !(newString.rangeOfCharacter(from: characterSet)?.isEmpty != false) {
307 | return false
308 | }
309 | return CGFloat(Double(newString) ?? 0) <= slider.maximumValue
310 | }
311 | }
312 |
--------------------------------------------------------------------------------
/Example/EFColorPicker.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
11 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; };
12 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
13 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
14 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
15 | B51C092BC469372831AA3531 /* Pods_EFColorPicker_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC1F8C2CEEC11F9A071D0BB6 /* Pods_EFColorPicker_Example.framework */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 12ED54D72250990400B84777 /* README_CN.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README_CN.md; path = ../README_CN.md; sourceTree = ""; };
20 | 4E0693B61CB89F59B63E299E /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; };
21 | 607FACD01AFB9204008FA782 /* EFColorPicker_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EFColorPicker_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
22 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
23 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
24 | 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
25 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
26 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
27 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
28 | 66363CE54747C0CE52946CEE /* Pods-EFColorPicker_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EFColorPicker_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-EFColorPicker_Tests/Pods-EFColorPicker_Tests.release.xcconfig"; sourceTree = ""; };
29 | A1767F18911529A8B2770D80 /* Pods-EFColorPicker_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EFColorPicker_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-EFColorPicker_Example/Pods-EFColorPicker_Example.release.xcconfig"; sourceTree = ""; };
30 | B80ED36874B9B1871306EF13 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; };
31 | C732E9AA81435E364115454A /* EFColorPicker.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = EFColorPicker.podspec; path = ../EFColorPicker.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
32 | C7AEF8D49DD9B32EE9F74210 /* Pods-EFColorPicker_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EFColorPicker_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-EFColorPicker_Tests/Pods-EFColorPicker_Tests.debug.xcconfig"; sourceTree = ""; };
33 | CBA3BDDD7D56ED74B0A8FD74 /* Pods-EFColorPicker_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EFColorPicker_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-EFColorPicker_Example/Pods-EFColorPicker_Example.debug.xcconfig"; sourceTree = ""; };
34 | D33A37D9FF5CC2221263E969 /* Pods_EFColorPicker_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EFColorPicker_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | FC1F8C2CEEC11F9A071D0BB6 /* Pods_EFColorPicker_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EFColorPicker_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
36 | /* End PBXFileReference section */
37 |
38 | /* Begin PBXFrameworksBuildPhase section */
39 | 607FACCD1AFB9204008FA782 /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | B51C092BC469372831AA3531 /* Pods_EFColorPicker_Example.framework in Frameworks */,
44 | );
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXFrameworksBuildPhase section */
48 |
49 | /* Begin PBXGroup section */
50 | 37A7F39F16F92CB73A28B206 /* Frameworks */ = {
51 | isa = PBXGroup;
52 | children = (
53 | FC1F8C2CEEC11F9A071D0BB6 /* Pods_EFColorPicker_Example.framework */,
54 | D33A37D9FF5CC2221263E969 /* Pods_EFColorPicker_Tests.framework */,
55 | );
56 | name = Frameworks;
57 | sourceTree = "";
58 | };
59 | 3B20BF72B132F6E76C2728D5 /* Pods */ = {
60 | isa = PBXGroup;
61 | children = (
62 | CBA3BDDD7D56ED74B0A8FD74 /* Pods-EFColorPicker_Example.debug.xcconfig */,
63 | A1767F18911529A8B2770D80 /* Pods-EFColorPicker_Example.release.xcconfig */,
64 | C7AEF8D49DD9B32EE9F74210 /* Pods-EFColorPicker_Tests.debug.xcconfig */,
65 | 66363CE54747C0CE52946CEE /* Pods-EFColorPicker_Tests.release.xcconfig */,
66 | );
67 | name = Pods;
68 | sourceTree = "";
69 | };
70 | 607FACC71AFB9204008FA782 = {
71 | isa = PBXGroup;
72 | children = (
73 | 607FACF51AFB993E008FA782 /* Podspec Metadata */,
74 | 607FACD21AFB9204008FA782 /* Example for EFColorPicker */,
75 | 607FACD11AFB9204008FA782 /* Products */,
76 | 3B20BF72B132F6E76C2728D5 /* Pods */,
77 | 37A7F39F16F92CB73A28B206 /* Frameworks */,
78 | );
79 | sourceTree = "";
80 | };
81 | 607FACD11AFB9204008FA782 /* Products */ = {
82 | isa = PBXGroup;
83 | children = (
84 | 607FACD01AFB9204008FA782 /* EFColorPicker_Example.app */,
85 | );
86 | name = Products;
87 | sourceTree = "";
88 | };
89 | 607FACD21AFB9204008FA782 /* Example for EFColorPicker */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */,
93 | 607FACD71AFB9204008FA782 /* ViewController.swift */,
94 | 607FACD91AFB9204008FA782 /* Main.storyboard */,
95 | 607FACDC1AFB9204008FA782 /* Images.xcassets */,
96 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
97 | 607FACD31AFB9204008FA782 /* Supporting Files */,
98 | );
99 | name = "Example for EFColorPicker";
100 | path = EFColorPicker;
101 | sourceTree = "";
102 | };
103 | 607FACD31AFB9204008FA782 /* Supporting Files */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 607FACD41AFB9204008FA782 /* Info.plist */,
107 | );
108 | name = "Supporting Files";
109 | sourceTree = "";
110 | };
111 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = {
112 | isa = PBXGroup;
113 | children = (
114 | C732E9AA81435E364115454A /* EFColorPicker.podspec */,
115 | 12ED54D72250990400B84777 /* README_CN.md */,
116 | 4E0693B61CB89F59B63E299E /* README.md */,
117 | B80ED36874B9B1871306EF13 /* LICENSE */,
118 | );
119 | name = "Podspec Metadata";
120 | sourceTree = "";
121 | };
122 | /* End PBXGroup section */
123 |
124 | /* Begin PBXNativeTarget section */
125 | 607FACCF1AFB9204008FA782 /* EFColorPicker_Example */ = {
126 | isa = PBXNativeTarget;
127 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "EFColorPicker_Example" */;
128 | buildPhases = (
129 | 22961CC1D1B1D7A58067A08C /* [CP] Check Pods Manifest.lock */,
130 | 607FACCC1AFB9204008FA782 /* Sources */,
131 | 607FACCD1AFB9204008FA782 /* Frameworks */,
132 | 607FACCE1AFB9204008FA782 /* Resources */,
133 | 6AB6E6DE27DE9C0E2D1B3602 /* [CP] Embed Pods Frameworks */,
134 | );
135 | buildRules = (
136 | );
137 | dependencies = (
138 | );
139 | name = EFColorPicker_Example;
140 | productName = EFColorPicker;
141 | productReference = 607FACD01AFB9204008FA782 /* EFColorPicker_Example.app */;
142 | productType = "com.apple.product-type.application";
143 | };
144 | /* End PBXNativeTarget section */
145 |
146 | /* Begin PBXProject section */
147 | 607FACC81AFB9204008FA782 /* Project object */ = {
148 | isa = PBXProject;
149 | attributes = {
150 | LastSwiftUpdateCheck = 0720;
151 | LastUpgradeCheck = 1020;
152 | ORGANIZATIONNAME = CocoaPods;
153 | TargetAttributes = {
154 | 607FACCF1AFB9204008FA782 = {
155 | CreatedOnToolsVersion = 6.3.1;
156 | LastSwiftMigration = 1020;
157 | };
158 | };
159 | };
160 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "EFColorPicker" */;
161 | compatibilityVersion = "Xcode 3.2";
162 | developmentRegion = en;
163 | hasScannedForEncodings = 0;
164 | knownRegions = (
165 | en,
166 | Base,
167 | );
168 | mainGroup = 607FACC71AFB9204008FA782;
169 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */;
170 | projectDirPath = "";
171 | projectRoot = "";
172 | targets = (
173 | 607FACCF1AFB9204008FA782 /* EFColorPicker_Example */,
174 | );
175 | };
176 | /* End PBXProject section */
177 |
178 | /* Begin PBXResourcesBuildPhase section */
179 | 607FACCE1AFB9204008FA782 /* Resources */ = {
180 | isa = PBXResourcesBuildPhase;
181 | buildActionMask = 2147483647;
182 | files = (
183 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */,
184 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
185 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
186 | );
187 | runOnlyForDeploymentPostprocessing = 0;
188 | };
189 | /* End PBXResourcesBuildPhase section */
190 |
191 | /* Begin PBXShellScriptBuildPhase section */
192 | 22961CC1D1B1D7A58067A08C /* [CP] Check Pods Manifest.lock */ = {
193 | isa = PBXShellScriptBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | );
197 | inputPaths = (
198 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
199 | "${PODS_ROOT}/Manifest.lock",
200 | );
201 | name = "[CP] Check Pods Manifest.lock";
202 | outputPaths = (
203 | "$(DERIVED_FILE_DIR)/Pods-EFColorPicker_Example-checkManifestLockResult.txt",
204 | );
205 | runOnlyForDeploymentPostprocessing = 0;
206 | shellPath = /bin/sh;
207 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
208 | showEnvVarsInLog = 0;
209 | };
210 | 6AB6E6DE27DE9C0E2D1B3602 /* [CP] Embed Pods Frameworks */ = {
211 | isa = PBXShellScriptBuildPhase;
212 | buildActionMask = 2147483647;
213 | files = (
214 | );
215 | inputPaths = (
216 | "${PODS_ROOT}/Target Support Files/Pods-EFColorPicker_Example/Pods-EFColorPicker_Example-frameworks.sh",
217 | "${BUILT_PRODUCTS_DIR}/EFColorPicker/EFColorPicker.framework",
218 | );
219 | name = "[CP] Embed Pods Frameworks";
220 | outputPaths = (
221 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EFColorPicker.framework",
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | shellPath = /bin/sh;
225 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-EFColorPicker_Example/Pods-EFColorPicker_Example-frameworks.sh\"\n";
226 | showEnvVarsInLog = 0;
227 | };
228 | /* End PBXShellScriptBuildPhase section */
229 |
230 | /* Begin PBXSourcesBuildPhase section */
231 | 607FACCC1AFB9204008FA782 /* Sources */ = {
232 | isa = PBXSourcesBuildPhase;
233 | buildActionMask = 2147483647;
234 | files = (
235 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */,
236 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | /* End PBXSourcesBuildPhase section */
241 |
242 | /* Begin PBXVariantGroup section */
243 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = {
244 | isa = PBXVariantGroup;
245 | children = (
246 | 607FACDA1AFB9204008FA782 /* Base */,
247 | );
248 | name = Main.storyboard;
249 | sourceTree = "";
250 | };
251 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = {
252 | isa = PBXVariantGroup;
253 | children = (
254 | 607FACDF1AFB9204008FA782 /* Base */,
255 | );
256 | name = LaunchScreen.xib;
257 | sourceTree = "";
258 | };
259 | /* End PBXVariantGroup section */
260 |
261 | /* Begin XCBuildConfiguration section */
262 | 607FACED1AFB9204008FA782 /* Debug */ = {
263 | isa = XCBuildConfiguration;
264 | buildSettings = {
265 | ALWAYS_SEARCH_USER_PATHS = NO;
266 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
267 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
268 | CLANG_CXX_LIBRARY = "libc++";
269 | CLANG_ENABLE_MODULES = YES;
270 | CLANG_ENABLE_OBJC_ARC = YES;
271 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
272 | CLANG_WARN_BOOL_CONVERSION = YES;
273 | CLANG_WARN_COMMA = YES;
274 | CLANG_WARN_CONSTANT_CONVERSION = YES;
275 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
277 | CLANG_WARN_EMPTY_BODY = YES;
278 | CLANG_WARN_ENUM_CONVERSION = YES;
279 | CLANG_WARN_INFINITE_RECURSION = YES;
280 | CLANG_WARN_INT_CONVERSION = YES;
281 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
282 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
286 | CLANG_WARN_STRICT_PROTOTYPES = YES;
287 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
288 | CLANG_WARN_UNREACHABLE_CODE = YES;
289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
290 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
291 | COPY_PHASE_STRIP = NO;
292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
293 | ENABLE_STRICT_OBJC_MSGSEND = YES;
294 | ENABLE_TESTABILITY = YES;
295 | GCC_C_LANGUAGE_STANDARD = gnu99;
296 | GCC_DYNAMIC_NO_PIC = NO;
297 | GCC_NO_COMMON_BLOCKS = YES;
298 | GCC_OPTIMIZATION_LEVEL = 0;
299 | GCC_PREPROCESSOR_DEFINITIONS = (
300 | "DEBUG=1",
301 | "$(inherited)",
302 | );
303 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
306 | GCC_WARN_UNDECLARED_SELECTOR = YES;
307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
308 | GCC_WARN_UNUSED_FUNCTION = YES;
309 | GCC_WARN_UNUSED_VARIABLE = YES;
310 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
311 | MTL_ENABLE_DEBUG_INFO = YES;
312 | ONLY_ACTIVE_ARCH = YES;
313 | SDKROOT = iphoneos;
314 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
315 | SWIFT_VERSION = 5.0;
316 | };
317 | name = Debug;
318 | };
319 | 607FACEE1AFB9204008FA782 /* Release */ = {
320 | isa = XCBuildConfiguration;
321 | buildSettings = {
322 | ALWAYS_SEARCH_USER_PATHS = NO;
323 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
325 | CLANG_CXX_LIBRARY = "libc++";
326 | CLANG_ENABLE_MODULES = YES;
327 | CLANG_ENABLE_OBJC_ARC = YES;
328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
329 | CLANG_WARN_BOOL_CONVERSION = YES;
330 | CLANG_WARN_COMMA = YES;
331 | CLANG_WARN_CONSTANT_CONVERSION = YES;
332 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
334 | CLANG_WARN_EMPTY_BODY = YES;
335 | CLANG_WARN_ENUM_CONVERSION = YES;
336 | CLANG_WARN_INFINITE_RECURSION = YES;
337 | CLANG_WARN_INT_CONVERSION = YES;
338 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
339 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
340 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
342 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
343 | CLANG_WARN_STRICT_PROTOTYPES = YES;
344 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
345 | CLANG_WARN_UNREACHABLE_CODE = YES;
346 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
348 | COPY_PHASE_STRIP = NO;
349 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
350 | ENABLE_NS_ASSERTIONS = NO;
351 | ENABLE_STRICT_OBJC_MSGSEND = YES;
352 | GCC_C_LANGUAGE_STANDARD = gnu99;
353 | GCC_NO_COMMON_BLOCKS = YES;
354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
356 | GCC_WARN_UNDECLARED_SELECTOR = YES;
357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
358 | GCC_WARN_UNUSED_FUNCTION = YES;
359 | GCC_WARN_UNUSED_VARIABLE = YES;
360 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
361 | MTL_ENABLE_DEBUG_INFO = NO;
362 | SDKROOT = iphoneos;
363 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
364 | SWIFT_VERSION = 5.0;
365 | VALIDATE_PRODUCT = YES;
366 | };
367 | name = Release;
368 | };
369 | 607FACF01AFB9204008FA782 /* Debug */ = {
370 | isa = XCBuildConfiguration;
371 | baseConfigurationReference = CBA3BDDD7D56ED74B0A8FD74 /* Pods-EFColorPicker_Example.debug.xcconfig */;
372 | buildSettings = {
373 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
374 | DEVELOPMENT_TEAM = "";
375 | INFOPLIST_FILE = EFColorPicker/Info.plist;
376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
377 | MARKETING_VERSION = 5.2.0;
378 | MODULE_NAME = ExampleApp;
379 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
380 | PRODUCT_NAME = "$(TARGET_NAME)";
381 | SWIFT_VERSION = 5.0;
382 | TARGETED_DEVICE_FAMILY = "1,2";
383 | };
384 | name = Debug;
385 | };
386 | 607FACF11AFB9204008FA782 /* Release */ = {
387 | isa = XCBuildConfiguration;
388 | baseConfigurationReference = A1767F18911529A8B2770D80 /* Pods-EFColorPicker_Example.release.xcconfig */;
389 | buildSettings = {
390 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
391 | DEVELOPMENT_TEAM = "";
392 | INFOPLIST_FILE = EFColorPicker/Info.plist;
393 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
394 | MARKETING_VERSION = 5.2.0;
395 | MODULE_NAME = ExampleApp;
396 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
397 | PRODUCT_NAME = "$(TARGET_NAME)";
398 | SWIFT_VERSION = 5.0;
399 | TARGETED_DEVICE_FAMILY = "1,2";
400 | };
401 | name = Release;
402 | };
403 | /* End XCBuildConfiguration section */
404 |
405 | /* Begin XCConfigurationList section */
406 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "EFColorPicker" */ = {
407 | isa = XCConfigurationList;
408 | buildConfigurations = (
409 | 607FACED1AFB9204008FA782 /* Debug */,
410 | 607FACEE1AFB9204008FA782 /* Release */,
411 | );
412 | defaultConfigurationIsVisible = 0;
413 | defaultConfigurationName = Release;
414 | };
415 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "EFColorPicker_Example" */ = {
416 | isa = XCConfigurationList;
417 | buildConfigurations = (
418 | 607FACF01AFB9204008FA782 /* Debug */,
419 | 607FACF11AFB9204008FA782 /* Release */,
420 | );
421 | defaultConfigurationIsVisible = 0;
422 | defaultConfigurationName = Release;
423 | };
424 | /* End XCConfigurationList section */
425 | };
426 | rootObject = 607FACC81AFB9204008FA782 /* Project object */;
427 | }
428 |
--------------------------------------------------------------------------------