├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── README_cn.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── defaults │ │ └── colorpickerapp │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── top │ │ │ └── defaults │ │ │ └── colorpickerapp │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout-land │ │ └── activity_main.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── top │ └── defaults │ └── colorpickerapp │ └── ExampleUnitTest.java ├── art ├── screen-record.gif ├── screen-shot-1.png └── screen-shot-2.png ├── build.gradle ├── colorpicker ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── defaults │ │ └── colorpicker │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── top │ │ │ └── defaults │ │ │ └── colorpicker │ │ │ ├── AlphaSliderView.java │ │ │ ├── BrightnessSliderView.java │ │ │ ├── ColorObservable.java │ │ │ ├── ColorObservableEmitter.java │ │ │ ├── ColorObserver.java │ │ │ ├── ColorPickerPopup.java │ │ │ ├── ColorPickerView.java │ │ │ ├── ColorSliderView.java │ │ │ ├── ColorWheelPalette.java │ │ │ ├── ColorWheelSelector.java │ │ │ ├── ColorWheelView.java │ │ │ ├── Constants.java │ │ │ ├── ThrottledTouchEventHandler.java │ │ │ └── Updatable.java │ └── res │ │ ├── anim │ │ ├── top_defaults_view_color_picker_popup_hide.xml │ │ └── top_defaults_view_color_picker_popup_show.xml │ │ ├── layout │ │ └── top_defaults_view_color_picker_popup.xml │ │ └── values │ │ ├── top_defaults_view_color_picker_attrs.xml │ │ └── top_defaults_view_color_picker_popup_styles.xml │ └── test │ └── java │ └── top │ └── defaults │ └── colorpicker │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | .idea/caches 43 | 44 | # Keystore files 45 | # Uncomment the following line if you do not want to check your keystore files in. 46 | #*.jks 47 | 48 | # External native build folder generated in Android Studio 2.2 and later 49 | .externalNativeBuild 50 | 51 | # Google Services (e.g. APIs or Firebase) 52 | google-services.json 53 | 54 | # Freeline 55 | freeline.py 56 | freeline/ 57 | freeline_project_description.json 58 | 59 | # fastlane 60 | fastlane/report.xml 61 | fastlane/Preview.html 62 | fastlane/screenshots 63 | fastlane/test_output 64 | fastlane/readme.md 65 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Hong Duan 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ColorPicker [![gitHub release](https://img.shields.io/github/release/duanhong169/ColorPicker.svg?style=social)](https://github.com/duanhong169/ColorPicker/releases) [![platform](https://img.shields.io/badge/platform-android-brightgreen.svg)](https://developer.android.com/index.html) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-ColorPicker-green.svg?style=flat)](https://android-arsenal.com/details/1/7068) [![license](https://img.shields.io/badge/license-Apache%202-green.svg)](https://github.com/duanhong169/ColorPicker/blob/master/LICENSE) 2 | 3 | English | [中文](README_cn.md) 4 | 5 | A `ColorPicker` for Android. Pick a color using color wheel and slider (HSV & alpha). 6 | 7 | 8 | 9 | ## Gradle 10 | 11 | ``` 12 | dependencies { 13 | implementation 'com.github.duanhong169:colorpicker:${latestVersion}' 14 | ... 15 | } 16 | ``` 17 | 18 | > Replace `${latestVersion}` with the latest version code. See [releases](https://github.com/duanhong169/ColorPicker/releases). 19 | 20 | ## Usage 21 | 22 | ### Using `ColorPickerPopup` 23 | 24 | ```java 25 | new ColorPickerPopup.Builder(this) 26 | .initialColor(Color.RED) // Set initial color 27 | .enableBrightness(true) // Enable brightness slider or not 28 | .enableAlpha(true) // Enable alpha slider or not 29 | .okTitle("Choose") 30 | .cancelTitle("Cancel") 31 | .showIndicator(true) 32 | .showValue(true) 33 | .build() 34 | .show(v, new ColorPickerPopup.ColorPickerObserver() { 35 | @Override 36 | public void onColorPicked(int color) { 37 | v.setBackgroundColor(color); 38 | } 39 | 40 | @Override 41 | public void onColor(int color, boolean fromUser) { 42 | 43 | } 44 | }); 45 | ``` 46 | 47 | ### Using `ColorPickerView` 48 | 49 | * Add `ColorPickerView` into your layout xml: 50 | 51 | ```xml 52 | 61 | ``` 62 | 63 | > See [`top_defaults_view_color_picker_attrs.xml`](./colorpicker/src/main/res/values/top_defaults_view_color_picker_attrs.xml) for all supported attributes. 64 | 65 | * Implement `ColorObserver` and subscribe to `ColorPickerView` to receive color updates from the `ColorPickerView`: 66 | 67 | ```java 68 | colorPickerView.subscribe((color, fromUser) -> { 69 | // use the color 70 | }); 71 | ``` 72 | 73 | * Set initial color: 74 | 75 | ```java 76 | colorPickerView.setInitialColor(0x7F313C93); 77 | ``` 78 | 79 | * Reset to initial color: 80 | 81 | ```java 82 | colorPickerView.reset(); 83 | ``` 84 | 85 | See a complete usage in the app sample code. 86 | 87 | ## License 88 | 89 | Copyright 2018 Hong Duan 90 | 91 | Licensed under the Apache License, Version 2.0 (the "License"); 92 | you may not use this file except in compliance with the License. 93 | You may obtain a copy of the License at 94 | 95 | http://www.apache.org/licenses/LICENSE-2.0 96 | 97 | Unless required by applicable law or agreed to in writing, software 98 | distributed under the License is distributed on an "AS IS" BASIS, 99 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 100 | See the License for the specific language governing permissions and 101 | limitations under the License. -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # ColorPicker [![gitHub release](https://img.shields.io/github/release/duanhong169/ColorPicker.svg?style=social)](https://github.com/duanhong169/ColorPicker/releases) [![platform](https://img.shields.io/badge/platform-android-brightgreen.svg)](https://developer.android.com/index.html) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-ColorPicker-green.svg?style=flat)](https://android-arsenal.com/details/1/7068) [![license](https://img.shields.io/badge/license-Apache%202-green.svg)](https://github.com/duanhong169/ColorPicker/blob/master/LICENSE) 2 | 3 | [English](README.md) | 中文 4 | 5 | Android颜色选择器。通过基于HSV颜色空间的调色盘和滑块来选择颜色,支持透明度值选择。 6 | 7 | 8 | 9 | ## Gradle 10 | 11 | ``` 12 | dependencies { 13 | implementation 'com.github.duanhong169:colorpicker:${latestVersion}' 14 | ... 15 | } 16 | ``` 17 | 18 | > 将上方的`${latestVersion}`替换为当前最新的版本号,最新版本号参见[releases](https://github.com/duanhong169/ColorPicker/releases)。 19 | 20 | ## 使用方法 21 | 22 | ### 使用弹出框`ColorPickerPopup` 23 | 24 | ```java 25 | new ColorPickerPopup.Builder(this) 26 | .initialColor(Color.RED) // Set initial color 27 | .enableBrightness(true) // Enable brightness slider or not 28 | .enableAlpha(true) // Enable alpha slider or not 29 | .okTitle("Choose") 30 | .cancelTitle("Cancel") 31 | .showIndicator(true) 32 | .showValue(true) 33 | .build() 34 | .show(v, new ColorPickerPopup.ColorPickerObserver() { 35 | @Override 36 | public void onColorPicked(int color) { 37 | v.setBackgroundColor(color); 38 | } 39 | 40 | @Override 41 | public void onColor(int color, boolean fromUser) { 42 | 43 | } 44 | }); 45 | ``` 46 | 47 | ### 直接使用视图`ColorPickerView` 48 | 49 | * 将`ColorPickerView`添加到需要的`layout.xml`文件中: 50 | 51 | ```xml 52 | 61 | ``` 62 | 63 | > 更多支持设置的属性请查阅[`top_defaults_view_color_picker_attrs.xml`](./colorpicker/src/main/res/values/top_defaults_view_color_picker_attrs.xml)。 64 | 65 | * 实现`ColorObserver`观察者接口并从`ColorPickerView`订阅颜色更新事件: 66 | 67 | ```java 68 | colorPickerView.subscribe((color, fromUser) -> { 69 | // use the color 70 | }); 71 | ``` 72 | 73 | * 设置选择器的初始颜色值: 74 | 75 | ```java 76 | colorPickerView.setInitialColor(0x7F313C93); 77 | ``` 78 | 79 | * 充值为初始颜色值: 80 | 81 | ```java 82 | colorPickerView.reset(); 83 | ``` 84 | 85 | 完整的示例代码请查阅项目所附app。 86 | 87 | ## License 88 | 89 | Copyright 2018 Hong Duan 90 | 91 | Licensed under the Apache License, Version 2.0 (the "License"); 92 | you may not use this file except in compliance with the License. 93 | You may obtain a copy of the License at 94 | 95 | http://www.apache.org/licenses/LICENSE-2.0 96 | 97 | Unless required by applicable law or agreed to in writing, software 98 | distributed under the License is distributed on an "AS IS" BASIS, 99 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 100 | See the License for the specific language governing permissions and 101 | limitations under the License. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "top.defaults.colorpicker" 7 | minSdkVersion 14 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_1_8 15 | targetCompatibility JavaVersion.VERSION_1_8 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(include: ['*.jar'], dir: 'libs') 27 | implementation 'com.android.support:appcompat-v7:27.1.1' 28 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 29 | implementation 'com.github.duanhong169:text-button:1.0.5' 30 | implementation 'com.jakewharton:butterknife:8.8.1' 31 | // implementation 'com.github.duanhong169:colorpicker:1.1.6' 32 | implementation project(':colorpicker') 33 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/top/defaults/colorpickerapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpickerapp; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("top.defaults.colorpicker", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/top/defaults/colorpickerapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpickerapp; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.ColorDrawable; 5 | import android.os.Build; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | import java.util.Locale; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import butterknife.OnClick; 17 | import top.defaults.colorpicker.ColorPickerPopup; 18 | import top.defaults.colorpicker.ColorPickerView; 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | 22 | private static final String SAVED_STATE_KEY_COLOR = "saved_state_key_color"; 23 | private static final int INITIAL_COLOR = 0xFFFF8000; 24 | 25 | @BindView(R.id.colorPicker) ColorPickerView colorPickerView; 26 | @BindView(R.id.pickedColor) View pickedColor; 27 | @BindView(R.id.colorHex) TextView colorHex; 28 | 29 | @OnClick(R.id.resetColor) 30 | void resetColor() { 31 | colorPickerView.reset(); 32 | } 33 | 34 | @OnClick({R.id.pickedColor, R.id.colorHex}) 35 | void popup(View v) { 36 | new ColorPickerPopup.Builder(this) 37 | .initialColor(colorPickerView.getColor()) 38 | .enableAlpha(true) 39 | .okTitle("Choose") 40 | .cancelTitle("Cancel") 41 | .showIndicator(true) 42 | .showValue(true) 43 | .onlyUpdateOnTouchEventUp(true) 44 | .build() 45 | .show(new ColorPickerPopup.ColorPickerObserver() { 46 | @Override 47 | public void onColorPicked(int color) { 48 | colorPickerView.setInitialColor(color); 49 | } 50 | }); 51 | } 52 | 53 | @Override 54 | protected void onCreate(Bundle savedInstanceState) { 55 | super.onCreate(savedInstanceState); 56 | setContentView(R.layout.activity_main); 57 | ButterKnife.bind(this); 58 | 59 | colorPickerView.subscribe((color, fromUser, shouldPropagate) -> { 60 | pickedColor.setBackgroundColor(color); 61 | colorHex.setText(colorHex(color)); 62 | 63 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 64 | getWindow().setStatusBarColor(color); 65 | } 66 | ActionBar actionBar = getSupportActionBar(); 67 | if (actionBar != null) { 68 | actionBar.setBackgroundDrawable(new ColorDrawable(color)); 69 | } 70 | }); 71 | 72 | int color = INITIAL_COLOR; 73 | if (savedInstanceState != null) { 74 | color = savedInstanceState.getInt(SAVED_STATE_KEY_COLOR, INITIAL_COLOR); 75 | } 76 | colorPickerView.setInitialColor(color); 77 | } 78 | 79 | @Override 80 | protected void onSaveInstanceState(Bundle outState) { 81 | super.onSaveInstanceState(outState); 82 | outState.putInt(SAVED_STATE_KEY_COLOR, colorPickerView.getColor()); 83 | } 84 | 85 | private String colorHex(int color) { 86 | int a = Color.alpha(color); 87 | int r = Color.red(color); 88 | int g = Color.green(color); 89 | int b = Color.blue(color); 90 | return String.format(Locale.getDefault(), "0x%02X%02X%02X%02X", a, r, g, b); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 28 | 29 | 41 | 42 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 27 | 28 | 39 | 40 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF8000 4 | #EF7800 5 | #F44336 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ColorPicker 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/top/defaults/colorpickerapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpickerapp; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /art/screen-record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/art/screen-record.gif -------------------------------------------------------------------------------- /art/screen-shot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/art/screen-shot-1.png -------------------------------------------------------------------------------- /art/screen-shot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/art/screen-shot-2.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.2.1' 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /colorpicker/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /colorpicker/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | ext { 4 | bintrayRepo = 'Hong' 5 | bintrayName = 'colorpicker' 6 | 7 | publishedGroupId = 'com.github.duanhong169' 8 | artifact = 'colorpicker' 9 | 10 | libraryDescription = 'A `ColorPicker` for android' 11 | libraryVersion = '1.1.6' 12 | 13 | gitUrl = 'https://github.com/duanhong169/ColorPicker.git' 14 | siteUrl = 'https://github.com/duanhong169/ColorPicker' 15 | 16 | licenseName = 'Apache License 2.0' 17 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 18 | allLicenses = ["Apache-2.0"] 19 | } 20 | 21 | android { 22 | compileSdkVersion 27 23 | defaultConfig { 24 | minSdkVersion 14 25 | targetSdkVersion 27 26 | versionCode 1 27 | versionName "1.0" 28 | 29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 30 | 31 | } 32 | 33 | buildTypes { 34 | release { 35 | minifyEnabled false 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | implementation 'com.android.support:appcompat-v7:27.1.1' 45 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 46 | implementation 'com.github.duanhong169:logger:1.0.0' 47 | implementation 'com.github.duanhong169:checkerboarddrawable:1.0.2' 48 | testImplementation 'junit:junit:4.12' 49 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 51 | } 52 | 53 | apply from: 'https://raw.githubusercontent.com/duanhong169/bintray-gradle/master/bintray.gradle' -------------------------------------------------------------------------------- /colorpicker/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /colorpicker/src/androidTest/java/top/defaults/colorpicker/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("top.defaults.view.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /colorpicker/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/AlphaSliderView.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.LinearGradient; 8 | import android.graphics.Paint; 9 | import android.graphics.Shader; 10 | import android.graphics.drawable.Drawable; 11 | import android.support.annotation.Nullable; 12 | import android.util.AttributeSet; 13 | 14 | import top.defaults.checkerboarddrawable.CheckerboardDrawable; 15 | 16 | public class AlphaSliderView extends ColorSliderView { 17 | 18 | private Bitmap backgroundBitmap; 19 | private Canvas backgroundCanvas; 20 | 21 | public AlphaSliderView(Context context) { 22 | super(context); 23 | } 24 | 25 | public AlphaSliderView(Context context, @Nullable AttributeSet attrs) { 26 | super(context, attrs); 27 | } 28 | 29 | public AlphaSliderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | } 32 | 33 | @Override 34 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 35 | super.onSizeChanged(w, h, oldw, oldh); 36 | backgroundBitmap = Bitmap.createBitmap((int) (w - 2 * selectorSize), 37 | (int) (h - selectorSize), Bitmap.Config.ARGB_8888); 38 | backgroundCanvas = new Canvas(backgroundBitmap); 39 | } 40 | 41 | @Override 42 | protected void onDraw(Canvas canvas) { 43 | Drawable drawable = CheckerboardDrawable.create(); 44 | drawable.setBounds(0, 0, backgroundCanvas.getWidth(), backgroundCanvas.getHeight()); 45 | drawable.draw(backgroundCanvas); 46 | canvas.drawBitmap(backgroundBitmap, selectorSize, selectorSize, null); 47 | super.onDraw(canvas); 48 | } 49 | 50 | @Override 51 | protected float resolveValue(int color) { 52 | return Color.alpha(color) / 255.f; 53 | } 54 | 55 | protected void configurePaint(Paint colorPaint) { 56 | float[] hsv = new float[3]; 57 | Color.colorToHSV(baseColor, hsv); 58 | int startColor = Color.HSVToColor(0, hsv); 59 | int endColor = Color.HSVToColor(255, hsv); 60 | Shader shader = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP); 61 | colorPaint.setShader(shader); 62 | } 63 | 64 | protected int assembleColor() { 65 | float[] hsv = new float[3]; 66 | Color.colorToHSV(baseColor, hsv); 67 | int alpha = (int) (currentValue * 255); 68 | return Color.HSVToColor(alpha, hsv); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/BrightnessSliderView.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.LinearGradient; 6 | import android.graphics.Paint; 7 | import android.graphics.Shader; 8 | import android.support.annotation.Nullable; 9 | import android.util.AttributeSet; 10 | 11 | public class BrightnessSliderView extends ColorSliderView { 12 | 13 | public BrightnessSliderView(Context context) { 14 | super(context); 15 | } 16 | 17 | public BrightnessSliderView(Context context, @Nullable AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public BrightnessSliderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | @Override 26 | protected float resolveValue(int color) { 27 | float[] hsv = new float[3]; 28 | Color.colorToHSV(color, hsv); 29 | return hsv[2]; 30 | } 31 | 32 | protected void configurePaint(Paint colorPaint) { 33 | float[] hsv = new float[3]; 34 | Color.colorToHSV(baseColor, hsv); 35 | hsv[2] = 0; 36 | int startColor = Color.HSVToColor(hsv); 37 | hsv[2] = 1; 38 | int endColor = Color.HSVToColor(hsv); 39 | Shader shader = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP); 40 | colorPaint.setShader(shader); 41 | } 42 | 43 | protected int assembleColor() { 44 | float[] hsv = new float[3]; 45 | Color.colorToHSV(baseColor, hsv); 46 | hsv[2] = currentValue; 47 | return Color.HSVToColor(hsv); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorObservable.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | public interface ColorObservable { 4 | 5 | void subscribe(ColorObserver observer); 6 | 7 | void unsubscribe(ColorObserver observer); 8 | 9 | int getColor(); 10 | } 11 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorObservableEmitter.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | class ColorObservableEmitter implements ColorObservable { 7 | 8 | private List observers = new ArrayList<>(); 9 | private int color; 10 | 11 | @Override 12 | public void subscribe(ColorObserver observer) { 13 | if (observer == null) return; 14 | observers.add(observer); 15 | } 16 | 17 | @Override 18 | public void unsubscribe(ColorObserver observer) { 19 | if (observer == null) return; 20 | observers.remove(observer); 21 | } 22 | 23 | @Override 24 | public int getColor() { 25 | return color; 26 | } 27 | 28 | void onColor(int color, boolean fromUser, boolean shouldPropagate) { 29 | this.color = color; 30 | for (ColorObserver observer : observers) { 31 | observer.onColor(color, fromUser, shouldPropagate); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorObserver.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | public interface ColorObserver { 4 | /** 5 | * Color has changed. 6 | * 7 | * @param color the new color 8 | * @param fromUser if this color is changed by user or not (programmatically) 9 | * @param shouldPropagate should this event be propagated to the observers (you can ignore this) 10 | */ 11 | void onColor(int color, boolean fromUser, boolean shouldPropagate); 12 | } 13 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorPickerPopup.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.ColorDrawable; 7 | import android.os.Build; 8 | import android.view.Gravity; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.PopupWindow; 13 | import android.widget.TextView; 14 | 15 | import java.util.Locale; 16 | 17 | import static android.content.Context.LAYOUT_INFLATER_SERVICE; 18 | 19 | public class ColorPickerPopup { 20 | 21 | private Context context; 22 | private PopupWindow popupWindow; 23 | private int initialColor; 24 | private boolean enableBrightness; 25 | private boolean enableAlpha; 26 | private String okTitle; 27 | private String cancelTitle; 28 | private boolean showIndicator; 29 | private boolean showValue; 30 | private boolean onlyUpdateOnTouchEventUp; 31 | 32 | private ColorPickerPopup(Builder builder) { 33 | this.context = builder.context; 34 | this.initialColor = builder.initialColor; 35 | this.enableBrightness = builder.enableBrightness; 36 | this.enableAlpha = builder.enableAlpha; 37 | this.okTitle = builder.okTitle; 38 | this.cancelTitle = builder.cancelTitle; 39 | this.showIndicator = builder.showIndicator; 40 | this.showValue = builder.showValue; 41 | this.onlyUpdateOnTouchEventUp = builder.onlyUpdateOnTouchEventUp; 42 | } 43 | 44 | public void show(final ColorPickerObserver observer) { 45 | show(null, observer); 46 | } 47 | 48 | public void show(View parent, final ColorPickerObserver observer) { 49 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE); 50 | if (inflater == null) return; 51 | 52 | @SuppressLint("InflateParams") 53 | View layout = inflater.inflate(R.layout.top_defaults_view_color_picker_popup, null); 54 | final ColorPickerView colorPickerView = layout.findViewById(R.id.colorPickerView); 55 | popupWindow = new PopupWindow(layout, ViewGroup.LayoutParams.WRAP_CONTENT, 56 | ViewGroup.LayoutParams.WRAP_CONTENT); 57 | popupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE)); 58 | popupWindow.setOutsideTouchable(true); 59 | colorPickerView.setInitialColor(initialColor); 60 | colorPickerView.setEnabledBrightness(enableBrightness); 61 | colorPickerView.setEnabledAlpha(enableAlpha); 62 | colorPickerView.setOnlyUpdateOnTouchEventUp(onlyUpdateOnTouchEventUp); 63 | colorPickerView.subscribe(observer); 64 | TextView cancel = layout.findViewById(R.id.cancel); 65 | cancel.setText(cancelTitle); 66 | cancel.setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View v) { 69 | popupWindow.dismiss(); 70 | } 71 | }); 72 | TextView ok = layout.findViewById(R.id.ok); 73 | ok.setText(okTitle); 74 | ok.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | popupWindow.dismiss(); 78 | if (observer != null) { 79 | observer.onColorPicked(colorPickerView.getColor()); 80 | } 81 | } 82 | }); 83 | 84 | final View colorIndicator = layout.findViewById(R.id.colorIndicator); 85 | final TextView colorHex = layout.findViewById(R.id.colorHex); 86 | 87 | colorIndicator.setVisibility(showIndicator ? View.VISIBLE : View.GONE); 88 | colorHex.setVisibility(showValue ? View.VISIBLE : View.GONE); 89 | 90 | if (showIndicator) { 91 | colorIndicator.setBackgroundColor(initialColor); 92 | } 93 | if (showValue) { 94 | colorHex.setText(colorHex(initialColor)); 95 | } 96 | colorPickerView.subscribe(new ColorObserver() { 97 | @Override 98 | public void onColor(int color, boolean fromUser, boolean shouldPropagate) { 99 | if (showIndicator) { 100 | colorIndicator.setBackgroundColor(color); 101 | } 102 | if (showValue) { 103 | colorHex.setText(colorHex(color)); 104 | } 105 | } 106 | }); 107 | 108 | if(Build.VERSION.SDK_INT >= 21){ 109 | popupWindow.setElevation(10.0f); 110 | } 111 | 112 | popupWindow.setAnimationStyle(R.style.TopDefaultsViewColorPickerPopupAnimation); 113 | if (parent == null) parent = layout; 114 | popupWindow.showAtLocation(parent, Gravity.CENTER, 0, 0); 115 | } 116 | 117 | public void dismiss() { 118 | if (popupWindow != null) { 119 | popupWindow.dismiss(); 120 | } 121 | } 122 | 123 | public static class Builder { 124 | 125 | private Context context; 126 | private int initialColor = Color.MAGENTA; 127 | private boolean enableBrightness = true; 128 | private boolean enableAlpha = false; 129 | private String okTitle = "OK"; 130 | private String cancelTitle = "Cancel"; 131 | private boolean showIndicator = true; 132 | private boolean showValue = true; 133 | private boolean onlyUpdateOnTouchEventUp = false; 134 | 135 | public Builder(Context context) { 136 | this.context = context; 137 | } 138 | 139 | public Builder initialColor(int color) { 140 | initialColor = color; 141 | return this; 142 | } 143 | 144 | public Builder enableBrightness(boolean enable) { 145 | enableBrightness = enable; 146 | return this; 147 | } 148 | 149 | 150 | public Builder enableAlpha(boolean enable) { 151 | enableAlpha = enable; 152 | return this; 153 | } 154 | 155 | public Builder okTitle(String title) { 156 | okTitle = title; 157 | return this; 158 | } 159 | 160 | public Builder cancelTitle(String title) { 161 | cancelTitle = title; 162 | return this; 163 | } 164 | 165 | public Builder showIndicator(boolean show) { 166 | showIndicator = show; 167 | return this; 168 | } 169 | 170 | public Builder showValue(boolean show) { 171 | showValue = show; 172 | return this; 173 | } 174 | 175 | public Builder onlyUpdateOnTouchEventUp(boolean only) { 176 | onlyUpdateOnTouchEventUp = only; 177 | return this; 178 | } 179 | 180 | public ColorPickerPopup build() { 181 | return new ColorPickerPopup(this); 182 | } 183 | } 184 | 185 | private String colorHex(int color) { 186 | int a = Color.alpha(color); 187 | int r = Color.red(color); 188 | int g = Color.green(color); 189 | int b = Color.blue(color); 190 | return String.format(Locale.getDefault(), "0x%02X%02X%02X%02X", a, r, g, b); 191 | } 192 | 193 | public abstract static class ColorPickerObserver implements ColorObserver { 194 | public abstract void onColorPicked(int color); 195 | 196 | @Override 197 | public final void onColor(int color, boolean fromUser, boolean shouldPropagate) { 198 | 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorPickerView.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Color; 6 | import android.support.annotation.Nullable; 7 | import android.util.AttributeSet; 8 | import android.view.ViewGroup; 9 | import android.widget.LinearLayout; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import top.defaults.logger.Logger; 15 | 16 | public class ColorPickerView extends LinearLayout implements ColorObservable { 17 | 18 | private ColorWheelView colorWheelView; 19 | private BrightnessSliderView brightnessSliderView; 20 | private AlphaSliderView alphaSliderView; 21 | private ColorObservable observableOnDuty; 22 | private boolean onlyUpdateOnTouchEventUp; 23 | 24 | private int initialColor = Color.BLACK; 25 | 26 | private int sliderMargin; 27 | private int sliderHeight; 28 | 29 | public ColorPickerView(Context context) { 30 | this(context, null); 31 | } 32 | 33 | public ColorPickerView(Context context, @Nullable AttributeSet attrs) { 34 | this(context, attrs, 0); 35 | } 36 | 37 | public ColorPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | setOrientation(VERTICAL); 40 | 41 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerView); 42 | boolean enableAlpha = typedArray.getBoolean(R.styleable.ColorPickerView_enableAlpha, false); 43 | boolean enableBrightness = typedArray.getBoolean(R.styleable.ColorPickerView_enableBrightness, true); 44 | onlyUpdateOnTouchEventUp = typedArray.getBoolean(R.styleable.ColorPickerView_onlyUpdateOnTouchEventUp, false); 45 | typedArray.recycle(); 46 | 47 | colorWheelView = new ColorWheelView(context); 48 | float density = getResources().getDisplayMetrics().density; 49 | int margin = (int) (8 * density); 50 | sliderMargin = 2 * margin; 51 | sliderHeight = (int) (24 * density); 52 | 53 | LinearLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 54 | ViewGroup.LayoutParams.WRAP_CONTENT); 55 | addView(colorWheelView, params); 56 | 57 | setEnabledBrightness(enableBrightness); 58 | setEnabledAlpha(enableAlpha); 59 | 60 | setPadding(margin, margin, margin, margin); 61 | } 62 | 63 | public void setOnlyUpdateOnTouchEventUp(boolean onlyUpdateOnTouchEventUp) { 64 | this.onlyUpdateOnTouchEventUp = onlyUpdateOnTouchEventUp; 65 | updateObservableOnDuty(); 66 | } 67 | 68 | @Override 69 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 70 | int maxWidth = MeasureSpec.getSize(widthMeasureSpec); 71 | int maxHeight = MeasureSpec.getSize(heightMeasureSpec); 72 | if (BuildConfig.DEBUG) { 73 | Logger.d("maxWidth: %d, maxHeight: %d", maxWidth, maxHeight); 74 | } 75 | 76 | int desiredWidth = maxHeight - (getPaddingTop() + getPaddingBottom()) + (getPaddingLeft() + getPaddingRight()); 77 | if (brightnessSliderView != null) { 78 | desiredWidth -= (sliderMargin + sliderHeight); 79 | } 80 | if (alphaSliderView != null){ 81 | desiredWidth -= (sliderMargin + sliderHeight); 82 | } 83 | 84 | if (BuildConfig.DEBUG) { 85 | Logger.d("desiredWidth: %d", desiredWidth); 86 | } 87 | 88 | int width = Math.min(maxWidth, desiredWidth); 89 | int height = width - (getPaddingLeft() + getPaddingRight()) + (getPaddingTop() + getPaddingBottom()); 90 | if (brightnessSliderView != null) { 91 | height += (sliderMargin + sliderHeight); 92 | } 93 | if (alphaSliderView != null) { 94 | height += (sliderMargin + sliderHeight); 95 | } 96 | 97 | if (BuildConfig.DEBUG) { 98 | Logger.d("width: %d, height: %d", width, height); 99 | } 100 | super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.getMode(widthMeasureSpec)), 101 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.getMode(heightMeasureSpec))); 102 | } 103 | 104 | public void setInitialColor(int color) { 105 | initialColor = color; 106 | colorWheelView.setColor(color, true); 107 | } 108 | 109 | public void setEnabledBrightness(boolean enable) { 110 | if (enable) { 111 | if (brightnessSliderView == null) { 112 | brightnessSliderView = new BrightnessSliderView(getContext()); 113 | LinearLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, sliderHeight); 114 | params.topMargin = sliderMargin; 115 | addView(brightnessSliderView, 1, params); 116 | } 117 | brightnessSliderView.bind(colorWheelView); 118 | updateObservableOnDuty(); 119 | } else { 120 | if (brightnessSliderView != null) { 121 | brightnessSliderView.unbind(); 122 | removeView(brightnessSliderView); 123 | brightnessSliderView = null; 124 | } 125 | updateObservableOnDuty(); 126 | } 127 | 128 | if (alphaSliderView != null) { 129 | setEnabledAlpha(true); 130 | } 131 | } 132 | 133 | public void setEnabledAlpha(boolean enable) { 134 | if (enable) { 135 | if (alphaSliderView == null) { 136 | alphaSliderView = new AlphaSliderView(getContext()); 137 | LinearLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, sliderHeight); 138 | params.topMargin = sliderMargin; 139 | addView(alphaSliderView, params); 140 | } 141 | 142 | ColorObservable bindTo = brightnessSliderView; 143 | if (bindTo == null) { 144 | bindTo = colorWheelView; 145 | } 146 | alphaSliderView.bind(bindTo); 147 | updateObservableOnDuty(); 148 | } else { 149 | if (alphaSliderView != null) { 150 | alphaSliderView.unbind(); 151 | removeView(alphaSliderView); 152 | alphaSliderView = null; 153 | } 154 | updateObservableOnDuty(); 155 | } 156 | } 157 | 158 | private void updateObservableOnDuty() { 159 | if (observableOnDuty != null) { 160 | for (ColorObserver observer: observers) { 161 | observableOnDuty.unsubscribe(observer); 162 | } 163 | } 164 | 165 | colorWheelView.setOnlyUpdateOnTouchEventUp(false); 166 | if (brightnessSliderView != null) { 167 | brightnessSliderView.setOnlyUpdateOnTouchEventUp(false); 168 | } 169 | if (alphaSliderView != null) { 170 | alphaSliderView.setOnlyUpdateOnTouchEventUp(false); 171 | } 172 | 173 | if (brightnessSliderView == null && alphaSliderView == null) { 174 | observableOnDuty = colorWheelView; 175 | colorWheelView.setOnlyUpdateOnTouchEventUp(onlyUpdateOnTouchEventUp); 176 | } else { 177 | if (alphaSliderView != null) { 178 | observableOnDuty = alphaSliderView; 179 | alphaSliderView.setOnlyUpdateOnTouchEventUp(onlyUpdateOnTouchEventUp); 180 | } else { 181 | observableOnDuty = brightnessSliderView; 182 | brightnessSliderView.setOnlyUpdateOnTouchEventUp(onlyUpdateOnTouchEventUp); 183 | } 184 | } 185 | 186 | if (observers != null) { 187 | for (ColorObserver observer : observers) { 188 | observableOnDuty.subscribe(observer); 189 | observer.onColor(observableOnDuty.getColor(), false, true); 190 | } 191 | } 192 | } 193 | 194 | public void reset() { 195 | colorWheelView.setColor(initialColor, true); 196 | } 197 | 198 | List observers = new ArrayList<>(); 199 | 200 | @Override 201 | public void subscribe(ColorObserver observer) { 202 | observableOnDuty.subscribe(observer); 203 | observers.add(observer); 204 | } 205 | 206 | @Override 207 | public void unsubscribe(ColorObserver observer) { 208 | observableOnDuty.unsubscribe(observer); 209 | observers.remove(observer); 210 | } 211 | 212 | @Override 213 | public int getColor() { 214 | return observableOnDuty.getColor(); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorSliderView.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.support.annotation.Nullable; 10 | import android.util.AttributeSet; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | 14 | public abstract class ColorSliderView extends View implements ColorObservable, Updatable { 15 | protected int baseColor = Color.WHITE; 16 | private Paint colorPaint; 17 | private Paint borderPaint; 18 | private Paint selectorPaint; 19 | 20 | private Path selectorPath; 21 | private Path currentSelectorPath = new Path(); 22 | protected float selectorSize; 23 | protected float currentValue = 1f; 24 | private boolean onlyUpdateOnTouchEventUp; 25 | 26 | private ColorObservableEmitter emitter = new ColorObservableEmitter(); 27 | private ThrottledTouchEventHandler handler = new ThrottledTouchEventHandler(this); 28 | 29 | public ColorSliderView(Context context) { 30 | this(context, null); 31 | } 32 | 33 | public ColorSliderView(Context context, @Nullable AttributeSet attrs) { 34 | this(context, attrs, 0); 35 | } 36 | 37 | public ColorSliderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 40 | borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 41 | borderPaint.setStyle(Paint.Style.STROKE); 42 | borderPaint.setStrokeWidth(0); 43 | borderPaint.setColor(Color.BLACK); 44 | selectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 45 | selectorPaint.setColor(Color.BLACK); 46 | selectorPath = new Path(); 47 | selectorPath.setFillType(Path.FillType.WINDING); 48 | } 49 | 50 | @Override 51 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 52 | configurePaint(colorPaint); 53 | selectorPath.reset(); 54 | selectorSize = h * 0.25f; 55 | selectorPath.moveTo(0, 0); 56 | selectorPath.lineTo(selectorSize * 2, 0); 57 | selectorPath.lineTo(selectorSize, selectorSize); 58 | selectorPath.close(); 59 | } 60 | 61 | @Override 62 | protected void onDraw(Canvas canvas) { 63 | float width = getWidth(); 64 | float height = getHeight(); 65 | canvas.drawRect(selectorSize, selectorSize, width - selectorSize, height, colorPaint); 66 | canvas.drawRect(selectorSize, selectorSize, width - selectorSize, height, borderPaint); 67 | selectorPath.offset(currentValue * (width - 2 * selectorSize), 0, currentSelectorPath); 68 | canvas.drawPath(currentSelectorPath, selectorPaint); 69 | } 70 | 71 | @SuppressLint("ClickableViewAccessibility") 72 | @Override 73 | public boolean onTouchEvent(MotionEvent event) { 74 | int action = event.getActionMasked(); 75 | switch (action) { 76 | case MotionEvent.ACTION_DOWN: 77 | case MotionEvent.ACTION_MOVE: 78 | handler.onTouchEvent(event); 79 | return true; 80 | case MotionEvent.ACTION_UP: 81 | update(event); 82 | return true; 83 | } 84 | return super.onTouchEvent(event); 85 | } 86 | 87 | @Override 88 | public void update(MotionEvent event) { 89 | updateValue(event.getX()); 90 | boolean isTouchUpEvent = event.getActionMasked() == MotionEvent.ACTION_UP; 91 | if (!onlyUpdateOnTouchEventUp || isTouchUpEvent) { 92 | emitter.onColor(assembleColor(), true, isTouchUpEvent); 93 | } 94 | } 95 | 96 | void setBaseColor(int color, boolean fromUser, boolean shouldPropagate) { 97 | baseColor = color; 98 | configurePaint(colorPaint); 99 | int targetColor = color; 100 | if (!fromUser) { 101 | // if not set by user (means programmatically), resolve currentValue from color value 102 | currentValue = resolveValue(color); 103 | } else { 104 | targetColor = assembleColor(); 105 | } 106 | 107 | if (!onlyUpdateOnTouchEventUp) { 108 | emitter.onColor(targetColor, fromUser, shouldPropagate); 109 | } else if (shouldPropagate) { 110 | emitter.onColor(targetColor, fromUser, true); 111 | } 112 | invalidate(); 113 | } 114 | 115 | private void updateValue(float eventX) { 116 | float left = selectorSize; 117 | float right = getWidth() - selectorSize; 118 | if (eventX < left) eventX = left; 119 | if (eventX > right) eventX = right; 120 | currentValue = (eventX - left) / (right - left); 121 | invalidate(); 122 | } 123 | 124 | protected abstract float resolveValue(int color); 125 | 126 | protected abstract void configurePaint(Paint colorPaint); 127 | 128 | protected abstract int assembleColor(); 129 | 130 | @Override 131 | public void subscribe(ColorObserver observer) { 132 | emitter.subscribe(observer); 133 | } 134 | 135 | @Override 136 | public void unsubscribe(ColorObserver observer) { 137 | emitter.unsubscribe(observer); 138 | } 139 | 140 | @Override 141 | public int getColor() { 142 | return emitter.getColor(); 143 | } 144 | 145 | public void setOnlyUpdateOnTouchEventUp(boolean onlyUpdateOnTouchEventUp) { 146 | this.onlyUpdateOnTouchEventUp = onlyUpdateOnTouchEventUp; 147 | } 148 | 149 | private ColorObserver bindObserver = new ColorObserver() { 150 | @Override 151 | public void onColor(int color, boolean fromUser, boolean shouldPropagate) { 152 | setBaseColor(color, fromUser, shouldPropagate); 153 | } 154 | }; 155 | 156 | private ColorObservable boundObservable; 157 | 158 | public void bind(ColorObservable colorObservable) { 159 | if (colorObservable != null) { 160 | colorObservable.subscribe(bindObserver); 161 | setBaseColor(colorObservable.getColor(), true, true); 162 | } 163 | boundObservable = colorObservable; 164 | } 165 | 166 | public void unbind() { 167 | if (boundObservable != null) { 168 | boundObservable.unsubscribe(bindObserver); 169 | boundObservable = null; 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorWheelPalette.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.RadialGradient; 8 | import android.graphics.Shader; 9 | import android.graphics.SweepGradient; 10 | import android.support.annotation.Nullable; 11 | import android.util.AttributeSet; 12 | import android.view.View; 13 | 14 | public class ColorWheelPalette extends View { 15 | 16 | private float radius; 17 | private float centerX; 18 | private float centerY; 19 | 20 | private Paint huePaint; 21 | private Paint saturationPaint; 22 | 23 | public ColorWheelPalette(Context context) { 24 | this(context, null); 25 | } 26 | 27 | public ColorWheelPalette(Context context, @Nullable AttributeSet attrs) { 28 | this(context, attrs, 0); 29 | } 30 | 31 | public ColorWheelPalette(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | huePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 34 | saturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 35 | } 36 | 37 | @Override 38 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 39 | int netWidth = w - getPaddingLeft() - getPaddingRight(); 40 | int netHeight = h - getPaddingTop() - getPaddingBottom(); 41 | radius = Math.min(netWidth, netHeight) * 0.5f; 42 | if (radius < 0) return; 43 | centerX = w * 0.5f; 44 | centerY = h * 0.5f; 45 | 46 | Shader hueShader = new SweepGradient(centerX, centerY, 47 | new int[]{Color.RED, Color.MAGENTA, Color.BLUE, Color.CYAN, Color.GREEN, Color.YELLOW, Color.RED}, 48 | null); 49 | huePaint.setShader(hueShader); 50 | 51 | Shader saturationShader = new RadialGradient(centerX, centerY, radius, 52 | Color.WHITE, 0x00FFFFFF, Shader.TileMode.CLAMP); 53 | saturationPaint.setShader(saturationShader); 54 | } 55 | 56 | @Override 57 | protected void onDraw(Canvas canvas) { 58 | canvas.drawCircle(centerX, centerY, radius, huePaint); 59 | canvas.drawCircle(centerX, centerY, radius, saturationPaint); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorWheelSelector.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.PointF; 8 | import android.support.annotation.Nullable; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | import static top.defaults.colorpicker.Constants.SELECTOR_RADIUS_DP; 13 | 14 | public class ColorWheelSelector extends View { 15 | 16 | private Paint selectorPaint; 17 | private float selectorRadiusPx = SELECTOR_RADIUS_DP * 3; 18 | private PointF currentPoint = new PointF(); 19 | 20 | public ColorWheelSelector(Context context) { 21 | this(context, null); 22 | } 23 | 24 | public ColorWheelSelector(Context context, @Nullable AttributeSet attrs) { 25 | this(context, attrs, 0); 26 | } 27 | 28 | public ColorWheelSelector(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 29 | super(context, attrs, defStyleAttr); 30 | 31 | selectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 32 | selectorPaint.setColor(Color.BLACK); 33 | selectorPaint.setStyle(Paint.Style.STROKE); 34 | selectorPaint.setStrokeWidth(2); 35 | } 36 | 37 | @Override 38 | protected void onDraw(Canvas canvas) { 39 | canvas.drawLine(currentPoint.x - selectorRadiusPx, currentPoint.y, 40 | currentPoint.x + selectorRadiusPx, currentPoint.y, selectorPaint); 41 | canvas.drawLine(currentPoint.x, currentPoint.y - selectorRadiusPx, 42 | currentPoint.x, currentPoint.y + selectorRadiusPx, selectorPaint); 43 | canvas.drawCircle(currentPoint.x, currentPoint.y, selectorRadiusPx * 0.66f, selectorPaint); 44 | } 45 | 46 | public void setSelectorRadiusPx(float selectorRadiusPx) { 47 | this.selectorRadiusPx = selectorRadiusPx; 48 | } 49 | 50 | public void setCurrentPoint(PointF currentPoint) { 51 | this.currentPoint = currentPoint; 52 | invalidate(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ColorWheelView.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.graphics.PointF; 7 | import android.support.annotation.Nullable; 8 | import android.util.AttributeSet; 9 | import android.view.MotionEvent; 10 | import android.view.ViewGroup; 11 | import android.widget.FrameLayout; 12 | 13 | import static top.defaults.colorpicker.Constants.SELECTOR_RADIUS_DP; 14 | 15 | /** 16 | * HSV color wheel 17 | */ 18 | public class ColorWheelView extends FrameLayout implements ColorObservable, Updatable { 19 | 20 | private float radius; 21 | private float centerX; 22 | private float centerY; 23 | 24 | private float selectorRadiusPx = SELECTOR_RADIUS_DP * 3; 25 | 26 | private PointF currentPoint = new PointF(); 27 | private int currentColor = Color.MAGENTA; 28 | private boolean onlyUpdateOnTouchEventUp; 29 | 30 | private ColorWheelSelector selector; 31 | 32 | private ColorObservableEmitter emitter = new ColorObservableEmitter(); 33 | private ThrottledTouchEventHandler handler = new ThrottledTouchEventHandler(this); 34 | 35 | public ColorWheelView(Context context) { 36 | this(context, null); 37 | } 38 | 39 | public ColorWheelView(Context context, @Nullable AttributeSet attrs) { 40 | this(context, attrs, 0); 41 | } 42 | 43 | public ColorWheelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 44 | super(context, attrs, defStyleAttr); 45 | selectorRadiusPx = SELECTOR_RADIUS_DP * getResources().getDisplayMetrics().density; 46 | 47 | { 48 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 49 | ColorWheelPalette palette = new ColorWheelPalette(context); 50 | int padding = (int) selectorRadiusPx; 51 | palette.setPadding(padding, padding, padding, padding); 52 | addView(palette, layoutParams); 53 | } 54 | 55 | { 56 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 57 | selector = new ColorWheelSelector(context); 58 | selector.setSelectorRadiusPx(selectorRadiusPx); 59 | addView(selector, layoutParams); 60 | } 61 | } 62 | 63 | @Override 64 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 65 | int maxWidth = MeasureSpec.getSize(widthMeasureSpec); 66 | int maxHeight = MeasureSpec.getSize(heightMeasureSpec); 67 | 68 | int width, height; 69 | width = height = Math.min(maxWidth, maxHeight); 70 | super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 71 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); 72 | } 73 | 74 | @Override 75 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 76 | int netWidth = w - getPaddingLeft() - getPaddingRight(); 77 | int netHeight = h - getPaddingTop() - getPaddingBottom(); 78 | radius = Math.min(netWidth, netHeight) * 0.5f - selectorRadiusPx; 79 | if (radius < 0) return; 80 | centerX = netWidth * 0.5f; 81 | centerY = netHeight * 0.5f; 82 | setColor(currentColor, false); 83 | } 84 | 85 | @SuppressLint("ClickableViewAccessibility") 86 | @Override 87 | public boolean onTouchEvent(MotionEvent event) { 88 | int action = event.getActionMasked(); 89 | switch (action) { 90 | case MotionEvent.ACTION_DOWN: 91 | case MotionEvent.ACTION_MOVE: 92 | handler.onTouchEvent(event); 93 | return true; 94 | case MotionEvent.ACTION_UP: 95 | update(event); 96 | return true; 97 | } 98 | return super.onTouchEvent(event); 99 | } 100 | 101 | @Override 102 | public void update(MotionEvent event) { 103 | float x = event.getX(); 104 | float y = event.getY(); 105 | boolean isTouchUpEvent = event.getActionMasked() == MotionEvent.ACTION_UP; 106 | if (!onlyUpdateOnTouchEventUp || isTouchUpEvent) { 107 | emitter.onColor(getColorAtPoint(x, y), true, isTouchUpEvent); 108 | } 109 | updateSelector(x, y); 110 | } 111 | 112 | private int getColorAtPoint(float eventX, float eventY) { 113 | float x = eventX - centerX; 114 | float y = eventY - centerY; 115 | double r = Math.sqrt(x * x + y * y); 116 | float[] hsv = {0, 0, 1}; 117 | hsv[0] = (float) (Math.atan2(y, -x) / Math.PI * 180f) + 180; 118 | hsv[1] = Math.max(0f, Math.min(1f, (float) (r / radius))); 119 | return Color.HSVToColor(hsv); 120 | } 121 | 122 | public void setOnlyUpdateOnTouchEventUp(boolean onlyUpdateOnTouchEventUp) { 123 | this.onlyUpdateOnTouchEventUp = onlyUpdateOnTouchEventUp; 124 | } 125 | 126 | public void setColor(int color, boolean shouldPropagate) { 127 | float[] hsv = new float[3]; 128 | Color.colorToHSV(color, hsv); 129 | float r = hsv[1] * radius; 130 | float radian = (float) (hsv[0] / 180f * Math.PI); 131 | updateSelector((float) (r * Math.cos(radian) + centerX), (float) (-r * Math.sin(radian) + centerY)); 132 | currentColor = color; 133 | if (!onlyUpdateOnTouchEventUp) { 134 | emitter.onColor(color, false, shouldPropagate); 135 | } 136 | } 137 | 138 | private void updateSelector(float eventX, float eventY) { 139 | float x = eventX - centerX; 140 | float y = eventY - centerY; 141 | double r = Math.sqrt(x * x + y * y); 142 | if (r > radius) { 143 | x *= radius / r; 144 | y *= radius / r; 145 | } 146 | currentPoint.x = x + centerX; 147 | currentPoint.y = y + centerY; 148 | selector.setCurrentPoint(currentPoint); 149 | } 150 | 151 | @Override 152 | public void subscribe(ColorObserver observer) { 153 | emitter.subscribe(observer); 154 | } 155 | 156 | @Override 157 | public void unsubscribe(ColorObserver observer) { 158 | emitter.unsubscribe(observer); 159 | } 160 | 161 | @Override 162 | public int getColor() { 163 | return emitter.getColor(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/Constants.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | class Constants { 4 | 5 | static final int EVENT_MIN_INTERVAL = 1000 / 60; // 16ms 6 | 7 | static final int SELECTOR_RADIUS_DP = 9; 8 | } 9 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/ThrottledTouchEventHandler.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.view.MotionEvent; 4 | 5 | class ThrottledTouchEventHandler { 6 | 7 | private int minInterval = Constants.EVENT_MIN_INTERVAL; 8 | private Updatable updatable; 9 | private long lastPassedEventTime = 0; 10 | 11 | ThrottledTouchEventHandler(Updatable updatable) { 12 | this(Constants.EVENT_MIN_INTERVAL, updatable); 13 | } 14 | 15 | private ThrottledTouchEventHandler(int minInterval, Updatable updatable) { 16 | this.minInterval = minInterval; 17 | this.updatable = updatable; 18 | } 19 | 20 | void onTouchEvent(MotionEvent event) { 21 | if (updatable == null) return; 22 | long current = System.currentTimeMillis(); 23 | if (current - lastPassedEventTime <= minInterval) { 24 | return; 25 | } 26 | lastPassedEventTime = current; 27 | updatable.update(event); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/top/defaults/colorpicker/Updatable.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import android.view.MotionEvent; 4 | 5 | public interface Updatable { 6 | 7 | void update(MotionEvent event); 8 | } 9 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/anim/top_defaults_view_color_picker_popup_hide.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/anim/top_defaults_view_color_picker_popup_show.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/layout/top_defaults_view_color_picker_popup.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 29 | 30 | 41 | 42 | 49 | 50 | 60 | 61 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/values/top_defaults_view_color_picker_attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/values/top_defaults_view_color_picker_popup_styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /colorpicker/src/test/java/top/defaults/colorpicker/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package top.defaults.colorpicker; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duanhong169/ColorPicker/7be88d07371865aa1075a633ef19b4077cda43d4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Dec 07 19:55:58 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':colorpicker' 2 | --------------------------------------------------------------------------------