├── demo
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ ├── styles.xml
│ │ │ └── colors.xml
│ │ ├── drawable
│ │ │ ├── ic_github_white_24dp.xml
│ │ │ └── ic_palette_white_24dp.xml
│ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ ├── values-v21
│ │ │ └── styles.xml
│ │ ├── xml
│ │ │ └── main.xml
│ │ ├── layout
│ │ │ └── activity_color_picker.xml
│ │ └── layout-v21
│ │ │ └── activity_color_picker.xml
│ │ ├── java
│ │ └── com
│ │ │ └── jaredrummler
│ │ │ └── android
│ │ │ └── colorpicker
│ │ │ └── demo
│ │ │ ├── DemoFragment.java
│ │ │ ├── BasePreferenceFragment.java
│ │ │ ├── ColorPickerActivity.java
│ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── jitpack.yml
├── library
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ └── cpv_alpha.png
│ │ ├── drawable-xhdpi
│ │ │ └── cpv_alpha.png
│ │ ├── drawable-xxhdpi
│ │ │ └── cpv_alpha.png
│ │ ├── values
│ │ │ ├── ids.xml
│ │ │ ├── dimen.xml
│ │ │ ├── styles.xml
│ │ │ ├── strings.xml
│ │ │ └── attrs.xml
│ │ ├── drawable
│ │ │ ├── cpv_ic_arrow_right_black_24dp.xml
│ │ │ ├── cpv_preset_checked.xml
│ │ │ ├── cpv_btn_background_pressed.xml
│ │ │ └── cpv_btn_background.xml
│ │ ├── layout
│ │ │ ├── cpv_preference_circle.xml
│ │ │ ├── cpv_preference_square.xml
│ │ │ ├── cpv_preference_circle_large.xml
│ │ │ ├── cpv_preference_square_large.xml
│ │ │ ├── cpv_color_item_circle.xml
│ │ │ ├── cpv_color_item_square.xml
│ │ │ ├── cpv_dialog_presets.xml
│ │ │ └── cpv_dialog_color_picker.xml
│ │ ├── values-pt
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ └── strings.xml
│ │ ├── values-ja
│ │ │ └── strings.xml
│ │ ├── values-zh
│ │ │ └── strings.xml
│ │ ├── values-it-rIT
│ │ │ └── strings.xml
│ │ ├── values-tr
│ │ │ └── strings.xml
│ │ ├── values-ar
│ │ │ └── strings.xml
│ │ ├── values-cs
│ │ │ └── strings.xml
│ │ ├── values-nl-rNL
│ │ │ └── strings.xml
│ │ ├── values-sk
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ └── strings.xml
│ │ ├── values-pl
│ │ │ └── strings.xml
│ │ ├── values-fr-rFR
│ │ │ └── strings.xml
│ │ └── values-de
│ │ │ └── strings.xml
│ │ └── java
│ │ └── com
│ │ └── jaredrummler
│ │ └── android
│ │ └── colorpicker
│ │ ├── ColorShape.java
│ │ ├── DrawingUtils.java
│ │ ├── NestedGridView.java
│ │ ├── ColorPickerDialogListener.java
│ │ ├── AlphaPatternDrawable.java
│ │ ├── ColorPaletteAdapter.java
│ │ ├── ColorPreferenceCompat.java
│ │ ├── ColorPreference.java
│ │ ├── ColorPanelView.java
│ │ └── ColorPickerView.java
├── proguard-rules.pro
├── gradle.properties
└── build.gradle
├── settings.gradle
├── gradle.properties
├── art
├── demo.gif
├── screenshot1.png
├── screenshot2.png
└── screenshot3.png
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── maven-push.gradle
├── .travis.yml
├── .gitignore
├── gradlew.bat
├── README.md
├── gradlew
└── LICENSE
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk11
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo', ':library'
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
--------------------------------------------------------------------------------
/art/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/art/demo.gif
--------------------------------------------------------------------------------
/art/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/art/screenshot1.png
--------------------------------------------------------------------------------
/art/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/art/screenshot2.png
--------------------------------------------------------------------------------
/art/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/art/screenshot3.png
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/demo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/demo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/cpv_alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/library/src/main/res/drawable-hdpi/cpv_alpha.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/cpv_alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/library/src/main/res/drawable-xhdpi/cpv_alpha.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/cpv_alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zacharee/colorpicker/master/library/src/main/res/drawable-xxhdpi/cpv_alpha.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat May 21 15:54:16 EDT 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cpv_ic_arrow_right_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cpv_preset_checked.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cpv_btn_background_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_preference_circle.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_preference_square.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Selecionar uma cor
5 | Predefinidos
6 | Personalizar
7 | Selecionar
8 | Transparência
9 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_preference_circle_large.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_preference_square_large.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Selecciona un color
5 | Predeterminados
6 | Personalizar
7 | Seleccionar
8 | Transparencia
9 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cpv_btn_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 6dp
4 | 66dp
5 | 34dp
6 | 58dp
7 | 50dp
8 | 8dp
9 | 28dp
10 | 40dp
11 |
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | android:
4 | components:
5 | - tools # Tools
6 | - platform-tools # Platform tools
7 | - build-tools-28.0.3 # Build tools version
8 | - android-28 # Target SDK version
9 | - extra-android-m2repository # Support repo
10 | - sys-img-armeabi-v7a-android-18 # Emulator
11 |
12 | jdk:
13 | - oraclejdk8
14 |
15 | script:
16 | - ./gradlew build
17 |
18 | branches:
19 | except:
20 | - gh-pages
21 |
22 | notifications:
23 | email: false
24 |
25 | sudo: false
26 |
27 | cache:
28 | directories:
29 | - $HOME/.gradle
--------------------------------------------------------------------------------
/demo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ########### Specifies intentionally untracked files to ignore ###########
2 |
3 | ### Gradle
4 | .gradle/
5 | build/
6 |
7 | ### IntelliJ IDEA
8 | /.idea
9 | *.iml
10 | *.iws
11 | captures/
12 | .navigation/
13 | local.properties
14 | bin/
15 | gen/
16 | out/
17 | *.apk
18 | *.ap_
19 |
20 | ### Android
21 | *.jks
22 | *.dex
23 |
24 | ### Java
25 | *.class
26 | hs_err_pid*
27 |
28 | ### Windows
29 | Desktop.ini
30 | Thumbs.db
31 | ehthumbs.db
32 |
33 | ### OSX
34 | .DS_Store
35 |
36 | ### Linux
37 | *~
38 | .fuse_hidden*
39 | .directory
40 | .Trash-*
41 |
42 | ### Logs
43 | *.log
44 |
45 | ### Crashlytics
46 | com_crashlytics_export_strings.xml
47 | crashlytics.properties
48 | crashlytics-build.properties
49 | fabric.properties
50 |
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_NAME=1.1.0
2 | VERSION_CODE=110
3 | GROUP=com.github.zacharee.colorpicker
4 | ARTIFACT_ID=library
5 | POM_NAME=library
6 | POM_ARTIFACT_ID=library
7 | POM_PACKAGING=aar
8 | POM_DESCRIPTION=A simple good looking color picker component for Android
9 | POM_URL=https://github.com/jaredrummler/ColorPicker
10 | POM_SCM_URL=https://github.com/jaredrummler/ColorPicker
11 | POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git
12 | POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git
13 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
14 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
15 | POM_LICENCE_DIST=repo
16 | POM_DEVELOPER_ID=jaredrummler
17 | POM_DEVELOPER_NAME=Jared Rummler
18 | SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots
19 | RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'maven-publish'
4 |
5 | group = 'com.github.zacharee.colorpicker'
6 |
7 | android {
8 | compileSdkVersion buildConfig.compileSdk
9 | defaultConfig {
10 | applicationId "com.jaredrummler.android.colorpicker.demo"
11 | minSdkVersion buildConfig.minSdk
12 | targetSdkVersion buildConfig.targetSdk
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | lintOptions {
23 | checkReleaseBuilds false
24 | abortOnError false
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation deps.androidx.appCompat
30 | implementation deps.androidx.preferences
31 | implementation project(':library')
32 | }
33 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 | 16dp
21 | 16dp
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_color_item_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
26 |
27 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_color_item_square.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 | Color Picker
20 | Settings
21 | Color Picker Dialog
22 | GitHub
23 |
24 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | apply plugin: 'maven-publish'
4 |
5 | group = 'com.github.zacharee.colorpicker'
6 |
7 | android {
8 | compileSdkVersion buildConfig.compileSdk
9 | resourcePrefix "cpv_"
10 | defaultConfig {
11 | minSdkVersion buildConfig.minSdk
12 | targetSdkVersion buildConfig.targetSdk
13 | }
14 | lintOptions {
15 | abortOnError false
16 | }
17 | }
18 |
19 | afterEvaluate {
20 | publishing {
21 | publications {
22 | release(MavenPublication) {
23 | from components.release
24 |
25 | groupId = 'com.github.zacharee.colorpicker'
26 | artifactId = 'library'
27 | }
28 | }
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation deps.androidx.appCompat
34 | implementation deps.androidx.preferences
35 | implementation deps.androidx.material
36 | }
37 |
38 | apply from: rootProject.file('gradle/maven-push.gradle')
39 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorShape.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import androidx.annotation.IntDef;
20 |
21 | /**
22 | * The shape of the color preview
23 | */
24 | @IntDef({ ColorShape.SQUARE, ColorShape.CIRCLE }) public @interface ColorShape {
25 |
26 | int SQUARE = 0;
27 |
28 | int CIRCLE = 1;
29 | }
30 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_github_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | 色を選択
19 | プリセット
20 | カスタム
21 | 選択
22 | 透明度
23 |
24 |
--------------------------------------------------------------------------------
/demo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
22 | 64dp
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | 选择颜色
19 | 预置颜色
20 | 自定义颜色
21 | 确认
22 | 透明度
23 | 確認
24 | "重啟 "
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-it-rIT/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 | Personalizzato
18 | Seleziona un Colore
19 | Predefiniti
20 | Seleziona
21 | Trasparenza
22 | Confermare
23 | Resettare
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | Renk Seçin
16 | Ön Ayarlar
17 | Özel
18 | Seç
19 | Şeffaflık
20 | Onaylamak
21 | Sıfırlamak
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | Select a Color
19 | Presets
20 | Custom
21 | Select
22 | Transparency
23 | Reset
24 | Confirm
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | اختر لونًا
19 | ألوان جاهزة
20 | ألوان معدلة
21 | اختر
22 | الشفافية
23 | إعادة تعيين
24 | تؤكد
25 |
26 |
--------------------------------------------------------------------------------
/library/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | Vyberte barvu
19 | Přednastavené
20 | Vlastní
21 | Vybrat
22 | Průhlednost
23 | Resetovat
24 | Potvrdit
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-nl-rNL/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | Selecteer een kleur
16 | Vooraf ingesteld
17 | Aangepast
18 | Kiezen
19 | Transparantie
20 | Reset
21 | Bevestigen
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | Vyberte farbu
19 | Prednastavené
20 | Vlastné
21 | Vybrať
22 | Priehľadnosť
23 | Obnoviť
24 | Birmovať
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | Выберите цвет
19 | Предустановки
20 | Особый
21 | Выбрать
22 | Прозрачность
23 | Сброс
24 | Подтвердить
25 |
26 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | Wybierz kolor
19 | Kolory domyślne
20 | Dostosuj
21 | Wybierz
22 | Przezroczystość
23 | Zresetować
24 | Potwierdzać
25 |
--------------------------------------------------------------------------------
/library/src/main/res/values-fr-rFR/strings.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | Sélectionner une couleur
15 | Présélections
16 | Personnalisée
17 | Valider
18 | Transparence
19 | Confirmer
20 | Réinitialiser
21 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 | Farbe auswählen
18 | Voreinstellungen
19 | Benutzerdefiniert
20 | Auswählen
21 | Transparenz
22 | Zurücksetzen
23 | Bestätigen
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/DrawingUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.util.DisplayMetrics;
21 | import android.util.TypedValue;
22 |
23 | final class DrawingUtils {
24 |
25 | static int dpToPx(Context c, float dipValue) {
26 | DisplayMetrics metrics = c.getResources().getDisplayMetrics();
27 | float val = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
28 | int res = (int) (val + 0.5); // Round
29 | // Ensure at least 1 pixel if val was > 0
30 | return res == 0 && val > 0 ? 1 : res;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.android.colorpicker.demo;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 | import androidx.preference.Preference;
6 |
7 | import com.jaredrummler.android.colorpicker.ColorPreferenceCompat;
8 |
9 | public class DemoFragment extends BasePreferenceFragment {
10 |
11 | private static final String TAG = "DemoFragment";
12 |
13 | private static final String KEY_DEFAULT_COLOR = "default_color";
14 |
15 | @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
16 | setPreferencesFromResource(R.xml.main, rootKey);
17 |
18 | // Example showing how we can get the new color when it is changed:
19 | ColorPreferenceCompat colorPreference = (ColorPreferenceCompat) findPreference(KEY_DEFAULT_COLOR);
20 | colorPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
21 | @Override public boolean onPreferenceChange(Preference preference, Object newValue) {
22 | if (KEY_DEFAULT_COLOR.equals(preference.getKey())) {
23 | String newDefaultColor = Integer.toHexString((int) newValue);
24 | Log.d(TAG, "New default color is: #" + newDefaultColor);
25 | }
26 | return true;
27 | }
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/demo/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_palette_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
32 |
33 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/NestedGridView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.util.AttributeSet;
21 | import android.widget.GridView;
22 | import androidx.annotation.RestrictTo;
23 |
24 | @RestrictTo(RestrictTo.Scope.LIBRARY) public class NestedGridView extends GridView {
25 |
26 | public NestedGridView(Context context) {
27 | super(context);
28 | }
29 |
30 | public NestedGridView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 | }
33 |
34 | public NestedGridView(Context context, AttributeSet attrs, int defStyle) {
35 | super(context, attrs, defStyle);
36 | }
37 |
38 | @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
39 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
40 | super.onMeasure(widthMeasureSpec, expandSpec);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerDialogListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import androidx.annotation.ColorInt;
20 |
21 | /**
22 | * Callback used for getting the selected color from a color picker dialog.
23 | */
24 | public interface ColorPickerDialogListener {
25 |
26 | /**
27 | * Callback that is invoked when a color is selected from the color picker dialog.
28 | *
29 | * @param dialogId The dialog id used to create the dialog instance.
30 | * @param color The selected color
31 | */
32 | void onColorSelected(int dialogId, @ColorInt int color);
33 |
34 | /**
35 | * Callback that is invoked when the color picker dialog was dismissed.
36 | *
37 | * @param dialogId The dialog id used to create the dialog instance.
38 | */
39 | void onDialogDismissed(int dialogId);
40 |
41 | /**
42 | * Callback that is invoked when the color of the dialog is reset.
43 | * @param dialogId
44 | * The dialog id used the create the dialog instance.
45 | */
46 | void onColorReset(int dialogId);
47 | }
48 |
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
20 |
21 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/demo/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.android.colorpicker.demo;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.os.Build;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import androidx.preference.Preference;
8 | import androidx.preference.PreferenceCategory;
9 | import androidx.preference.PreferenceFragmentCompat;
10 | import androidx.preference.PreferenceGroupAdapter;
11 | import androidx.preference.PreferenceScreen;
12 | import androidx.preference.PreferenceViewHolder;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | // Fix for PreferenceFragmentCompat spacing.
16 | //
17 | // https://stackoverflow.com/questions/18509369
18 | // https://issuetracker.google.com/issues/111907042
19 | // https://issuetracker.google.com/issues/116170936
20 | //
21 | // I never wanted to support the preference fragment compat library. It sucks!
22 | // Give the developers what they want.. yeah.. your welcome. :P
23 |
24 | public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
25 |
26 | @Override protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
27 | return new PreferenceGroupAdapter(preferenceScreen) {
28 | @SuppressLint("RestrictedApi") @Override public void onBindViewHolder(PreferenceViewHolder holder, int position) {
29 | super.onBindViewHolder(holder, position);
30 | Preference preference = getItem(position);
31 | if (preference instanceof PreferenceCategory) {
32 | setZeroPaddingToLayoutChildren(holder.itemView);
33 | } else {
34 | View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
35 | if (iconFrame != null) {
36 | iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
37 | }
38 | }
39 | }
40 | };
41 | }
42 |
43 | private void setZeroPaddingToLayoutChildren(View view) {
44 | if (!(view instanceof ViewGroup)) return;
45 | ViewGroup viewGroup = (ViewGroup) view;
46 | int childCount = viewGroup.getChildCount();
47 | for (int i = 0; i < childCount; i++) {
48 | setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
50 | viewGroup.setPaddingRelative(0, viewGroup.getPaddingTop(), viewGroup.getPaddingEnd(),
51 | viewGroup.getPaddingBottom());
52 | } else {
53 | viewGroup.setPadding(0, viewGroup.getPaddingTop(), viewGroup.getPaddingRight(), viewGroup.getPaddingBottom());
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker.demo;
18 |
19 | import android.content.SharedPreferences;
20 | import android.graphics.PixelFormat;
21 | import android.os.Bundle;
22 | import android.preference.PreferenceManager;
23 | import android.view.View;
24 | import android.widget.Button;
25 | import android.widget.LinearLayout;
26 | import androidx.appcompat.app.AppCompatActivity;
27 | import com.jaredrummler.android.colorpicker.ColorPanelView;
28 | import com.jaredrummler.android.colorpicker.ColorPickerView;
29 | import com.jaredrummler.android.colorpicker.ColorPickerView.OnColorChangedListener;
30 |
31 | public class ColorPickerActivity extends AppCompatActivity implements OnColorChangedListener, View.OnClickListener {
32 |
33 | private ColorPickerView colorPickerView;
34 | private ColorPanelView newColorPanelView;
35 |
36 | @Override protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | getWindow().setFormat(PixelFormat.RGBA_8888);
39 |
40 | setContentView(R.layout.activity_color_picker);
41 |
42 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
43 | int initialColor = prefs.getInt("color_3", 0xFF000000);
44 |
45 | colorPickerView = (ColorPickerView) findViewById(R.id.cpv_color_picker_view);
46 | ColorPanelView colorPanelView = (ColorPanelView) findViewById(R.id.cpv_color_panel_old);
47 | newColorPanelView = (ColorPanelView) findViewById(R.id.cpv_color_panel_new);
48 |
49 | Button btnOK = (Button) findViewById(R.id.okButton);
50 | Button btnCancel = (Button) findViewById(R.id.cancelButton);
51 |
52 | ((LinearLayout) colorPanelView.getParent()).setPadding(colorPickerView.getPaddingLeft(), 0,
53 | colorPickerView.getPaddingRight(), 0);
54 |
55 | colorPickerView.setOnColorChangedListener(this);
56 | colorPickerView.setColor(initialColor, true);
57 | colorPanelView.setColor(initialColor);
58 |
59 | btnOK.setOnClickListener(this);
60 | btnCancel.setOnClickListener(this);
61 | }
62 |
63 | @Override public void onColorChanged(int newColor) {
64 | newColorPanelView.setColor(colorPickerView.getColor());
65 | }
66 |
67 | @Override public void onClick(View v) {
68 | switch (v.getId()) {
69 | case R.id.okButton:
70 | SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit();
71 | edit.putInt("color_3", colorPickerView.getColor());
72 | edit.apply();
73 | finish();
74 | break;
75 | case R.id.cancelButton:
76 | finish();
77 | break;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_dialog_presets.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
29 |
30 |
38 |
39 |
45 |
46 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
68 |
69 |
76 |
77 |
85 |
86 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker.demo;
18 |
19 | import android.content.ActivityNotFoundException;
20 | import android.content.Intent;
21 | import android.graphics.Color;
22 | import android.net.Uri;
23 | import android.os.Bundle;
24 | import android.util.Log;
25 | import android.view.Menu;
26 | import android.view.MenuItem;
27 | import android.widget.Toast;
28 | import androidx.appcompat.app.AppCompatActivity;
29 | import com.jaredrummler.android.colorpicker.ColorPickerDialog;
30 | import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
31 |
32 | public class MainActivity extends AppCompatActivity implements ColorPickerDialogListener {
33 |
34 | private static final String TAG = "MainActivity";
35 |
36 | // Give your color picker dialog unique IDs if you have multiple dialogs.
37 | private static final int DIALOG_ID = 0;
38 |
39 |
40 | @Override protected void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | if (savedInstanceState == null) {
43 | getSupportFragmentManager().beginTransaction().add(android.R.id.content, new DemoFragment()).commit();
44 | }
45 | }
46 |
47 | @Override public boolean onCreateOptionsMenu(Menu menu) {
48 | getMenuInflater().inflate(R.menu.main, menu);
49 | return true;
50 | }
51 |
52 | @Override public boolean onOptionsItemSelected(MenuItem item) {
53 | switch (item.getItemId()) {
54 | case R.id.menu_color_picker_dialog:
55 | ColorPickerDialog.newBuilder()
56 | .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
57 | .setAllowPresets(false)
58 | .setDialogId(DIALOG_ID)
59 | .setColor(Color.BLACK)
60 | .setShowAlphaSlider(true)
61 | .show(this);
62 | return true;
63 | case R.id.menu_github:
64 | try {
65 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/jaredrummler/ColorPicker")));
66 | } catch (ActivityNotFoundException ignored) {
67 | }
68 | return true;
69 | }
70 | return super.onOptionsItemSelected(item);
71 | }
72 |
73 | @Override public void onColorSelected(int dialogId, int color) {
74 | Log.d(TAG, "onColorSelected() called with: dialogId = [" + dialogId + "], color = [" + color + "]");
75 | switch (dialogId) {
76 | case DIALOG_ID:
77 | // We got result from the dialog that is shown when clicking on the icon in the action bar.
78 | Toast.makeText(MainActivity.this, "Selected Color: #" + Integer.toHexString(color), Toast.LENGTH_SHORT).show();
79 | break;
80 | }
81 | }
82 |
83 | @Override public void onDialogDismissed(int dialogId) {
84 | Log.d(TAG, "onDialogDismissed() called with: dialogId = [" + dialogId + "]");
85 | }
86 |
87 | @Override
88 | public void onColorReset(int dialogId) {
89 |
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | #3F51B5
21 | #303F9F
22 | #FF4081
23 |
24 |
25 | - @color/md_red_500
26 | - @color/md_pink_500
27 | - @color/md_purple_500
28 | - @color/md_deep_purple_500
29 | - @color/md_indigo_500
30 | - @color/md_blue_500
31 | - @color/md_light_blue_500
32 | - @color/md_cyan_500
33 | - @color/md_teal_500
34 | - @color/md_green_500
35 | - @color/md_light_green_500
36 | - @color/md_lime_500
37 | - @color/md_yellow_500
38 | - @color/md_amber_500
39 | - @color/md_orange_500
40 | - @color/md_deep_orange_500
41 | - @color/md_brown_500
42 | - @color/md_grey_500
43 | - @color/md_blue_grey_500
44 | - @color/md_white
45 |
46 |
47 |
48 | #f44336
49 |
50 |
51 | #e91e63
52 |
53 |
54 | #9c27b0
55 |
56 |
57 | #673ab7
58 |
59 |
60 | #3f51b5
61 |
62 |
63 | #2196f3
64 |
65 |
66 | #03a9f4
67 |
68 |
69 | #00bcd4
70 |
71 |
72 | #009688
73 |
74 |
75 | #4caf50
76 |
77 |
78 | #8bc34a
79 |
80 |
81 | #cddc39
82 |
83 |
84 | #ffeb3b
85 |
86 |
87 | #ffc107
88 |
89 |
90 | #ff9800
91 |
92 |
93 | #ff5722
94 |
95 |
96 | #795548
97 |
98 |
99 | #9e9e9e
100 |
101 | #000000
102 |
103 | #ffffff
104 |
105 |
106 | #607d8b
107 |
108 |
109 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cpv_dialog_color_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
23 |
24 |
30 |
31 |
37 |
38 |
48 |
49 |
55 |
56 |
61 |
62 |
72 |
73 |
80 |
81 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/demo/src/main/res/xml/main.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
27 |
33 |
34 |
41 |
42 |
51 |
52 |
61 |
62 |
72 |
73 |
77 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/gradle/maven-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven-publish'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
31 | : "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | // uploadArchives {
44 | // repositories {
45 | // mavenDeployer {
46 | //// beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 | //
48 | // pom.groupId = GROUP
49 | // pom.artifactId = POM_ARTIFACT_ID
50 | // pom.version = VERSION_NAME
51 | //
52 | // repository(url: getReleaseRepositoryUrl()) {
53 | // authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | // }
55 | // snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | // authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | // }
58 | //
59 | // pom.project {
60 | // name POM_NAME
61 | // packaging POM_PACKAGING
62 | // description POM_DESCRIPTION
63 | // url POM_URL
64 | //
65 | // scm {
66 | // url POM_SCM_URL
67 | // connection POM_SCM_CONNECTION
68 | // developerConnection POM_SCM_DEV_CONNECTION
69 | // }
70 | //
71 | // licenses {
72 | // license {
73 | // name POM_LICENCE_NAME
74 | // url POM_LICENCE_URL
75 | // distribution POM_LICENCE_DIST
76 | // }
77 | // }
78 | //
79 | // developers {
80 | // developer {
81 | // id POM_DEVELOPER_ID
82 | // name POM_DEVELOPER_NAME
83 | // }
84 | // }
85 | // }
86 | // }
87 | // }
88 | // }
89 |
90 | // signing {
91 | // required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
92 | // sign configurations.archives
93 | // }
94 |
95 | task androidJavadocs(type: Javadoc) {
96 | source = android.sourceSets.main.java.srcDirs
97 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
98 | if (JavaVersion.current().isJava8Compatible()) {
99 | options.addStringOption('Xdoclint:none', '-quiet')
100 | }
101 | failOnError false
102 | }
103 |
104 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
105 | classifier = 'javadoc'
106 | from androidJavadocs.destinationDir
107 | }
108 |
109 | task androidSourcesJar(type: Jar) {
110 | classifier = 'sources'
111 | from android.sourceSets.main.java.sourceFiles
112 | }
113 |
114 | artifacts {
115 | archives androidSourcesJar
116 | archives androidJavadocsJar
117 | }
118 | }
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_color_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
28 |
29 |
35 |
36 |
42 |
43 |
52 |
53 |
61 |
62 |
71 |
72 |
79 |
80 |
81 |
82 |
89 |
90 |
98 |
99 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout-v21/activity_color_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
28 |
29 |
35 |
36 |
43 |
44 |
53 |
54 |
62 |
63 |
73 |
74 |
82 |
83 |
84 |
85 |
92 |
93 |
101 |
102 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/AlphaPatternDrawable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.graphics.Bitmap;
20 | import android.graphics.Bitmap.Config;
21 | import android.graphics.Canvas;
22 | import android.graphics.ColorFilter;
23 | import android.graphics.Paint;
24 | import android.graphics.Rect;
25 | import android.graphics.drawable.Drawable;
26 |
27 | /**
28 | * This drawable will draw a simple white and gray chessboard pattern.
29 | * It's the pattern you will often see as a background behind a partly transparent image in many applications.
30 | */
31 | class AlphaPatternDrawable extends Drawable {
32 |
33 | private int rectangleSize = 10;
34 |
35 | private Paint paint = new Paint();
36 | private Paint paintWhite = new Paint();
37 | private Paint paintGray = new Paint();
38 |
39 | private int numRectanglesHorizontal;
40 | private int numRectanglesVertical;
41 |
42 | /**
43 | * Bitmap in which the pattern will be cached.
44 | * This is so the pattern will not have to be recreated each time draw() gets called.
45 | * Because recreating the pattern i rather expensive. I will only be recreated if the size changes.
46 | */
47 | private Bitmap bitmap;
48 |
49 | AlphaPatternDrawable(int rectangleSize) {
50 | this.rectangleSize = rectangleSize;
51 | paintWhite.setColor(0xFFFFFFFF);
52 | paintGray.setColor(0xFFCBCBCB);
53 | }
54 |
55 | @Override public void draw(Canvas canvas) {
56 | if (bitmap != null && !bitmap.isRecycled()) {
57 | canvas.drawBitmap(bitmap, null, getBounds(), paint);
58 | }
59 | }
60 |
61 | @Override public int getOpacity() {
62 | return 0;
63 | }
64 |
65 | @Override public void setAlpha(int alpha) {
66 | throw new UnsupportedOperationException("Alpha is not supported by this drawable.");
67 | }
68 |
69 | @Override public void setColorFilter(ColorFilter cf) {
70 | throw new UnsupportedOperationException("ColorFilter is not supported by this drawable.");
71 | }
72 |
73 | @Override protected void onBoundsChange(Rect bounds) {
74 | super.onBoundsChange(bounds);
75 | int height = bounds.height();
76 | int width = bounds.width();
77 | numRectanglesHorizontal = (int) Math.ceil((width / rectangleSize));
78 | numRectanglesVertical = (int) Math.ceil(height / rectangleSize);
79 | generatePatternBitmap();
80 | }
81 |
82 | /**
83 | * This will generate a bitmap with the pattern as big as the rectangle we were allow to draw on.
84 | * We do this to chache the bitmap so we don't need to recreate it each time draw() is called since it takes a few
85 | * milliseconds
86 | */
87 | private void generatePatternBitmap() {
88 | if (getBounds().width() <= 0 || getBounds().height() <= 0) {
89 | return;
90 | }
91 |
92 | bitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);
93 | Canvas canvas = new Canvas(bitmap);
94 |
95 | Rect r = new Rect();
96 | boolean verticalStartWhite = true;
97 | for (int i = 0; i <= numRectanglesVertical; i++) {
98 | boolean isWhite = verticalStartWhite;
99 | for (int j = 0; j <= numRectanglesHorizontal; j++) {
100 | r.top = i * rectangleSize;
101 | r.left = j * rectangleSize;
102 | r.bottom = r.top + rectangleSize;
103 | r.right = r.left + rectangleSize;
104 | canvas.drawRect(r, isWhite ? paintWhite : paintGray);
105 | isWhite = !isWhite;
106 | }
107 | verticalStartWhite = !verticalStartWhite;
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPaletteAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.graphics.Color;
21 | import android.graphics.PorterDuff;
22 | import android.view.View;
23 | import android.view.ViewGroup;
24 | import android.widget.BaseAdapter;
25 | import android.widget.ImageView;
26 | import androidx.core.graphics.ColorUtils;
27 |
28 | class ColorPaletteAdapter extends BaseAdapter {
29 |
30 | /*package*/ final OnColorSelectedListener listener;
31 | /*package*/ final int[] colors;
32 | /*package*/ int selectedPosition;
33 | /*package*/ int colorShape;
34 |
35 | ColorPaletteAdapter(OnColorSelectedListener listener, int[] colors, int selectedPosition,
36 | @ColorShape int colorShape) {
37 | this.listener = listener;
38 | this.colors = colors;
39 | this.selectedPosition = selectedPosition;
40 | this.colorShape = colorShape;
41 | }
42 |
43 | @Override public int getCount() {
44 | return colors.length;
45 | }
46 |
47 | @Override public Object getItem(int position) {
48 | return colors[position];
49 | }
50 |
51 | @Override public long getItemId(int position) {
52 | return position;
53 | }
54 |
55 | @Override public View getView(int position, View convertView, ViewGroup parent) {
56 | final ViewHolder holder;
57 | if (convertView == null) {
58 | holder = new ViewHolder(parent.getContext());
59 | convertView = holder.view;
60 | } else {
61 | holder = (ViewHolder) convertView.getTag();
62 | }
63 | holder.setup(position);
64 | return convertView;
65 | }
66 |
67 | void selectNone() {
68 | selectedPosition = -1;
69 | notifyDataSetChanged();
70 | }
71 |
72 | interface OnColorSelectedListener {
73 |
74 | void onColorSelected(int color);
75 | }
76 |
77 | private final class ViewHolder {
78 |
79 | View view;
80 | ColorPanelView colorPanelView;
81 | ImageView imageView;
82 | int originalBorderColor;
83 |
84 | ViewHolder(Context context) {
85 | int layoutResId;
86 | if (colorShape == ColorShape.SQUARE) {
87 | layoutResId = R.layout.cpv_color_item_square;
88 | } else {
89 | layoutResId = R.layout.cpv_color_item_circle;
90 | }
91 | view = View.inflate(context, layoutResId, null);
92 | colorPanelView = (ColorPanelView) view.findViewById(R.id.cpv_color_panel_view);
93 | imageView = (ImageView) view.findViewById(R.id.cpv_color_image_view);
94 | originalBorderColor = colorPanelView.getBorderColor();
95 | view.setTag(this);
96 | }
97 |
98 | void setup(int position) {
99 | int color = colors[position];
100 | int alpha = Color.alpha(color);
101 | colorPanelView.setColor(color);
102 | imageView.setImageResource(selectedPosition == position ? R.drawable.cpv_preset_checked : 0);
103 | if (alpha != 255) {
104 | if (alpha <= ColorPickerDialog.ALPHA_THRESHOLD) {
105 | colorPanelView.setBorderColor(color | 0xFF000000);
106 | imageView.setColorFilter(/*color | 0xFF000000*/Color.BLACK, PorterDuff.Mode.SRC_IN);
107 | } else {
108 | colorPanelView.setBorderColor(originalBorderColor);
109 | imageView.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
110 | }
111 | } else {
112 | setColorFilter(position);
113 | }
114 | setOnClickListener(position);
115 | }
116 |
117 | private void setOnClickListener(final int position) {
118 | colorPanelView.setOnClickListener(new View.OnClickListener() {
119 | @Override public void onClick(View v) {
120 | if (selectedPosition != position) {
121 | selectedPosition = position;
122 | notifyDataSetChanged();
123 | }
124 | listener.onColorSelected(colors[position]);
125 | }
126 | });
127 | colorPanelView.setOnLongClickListener(new View.OnLongClickListener() {
128 | @Override public boolean onLongClick(View v) {
129 | colorPanelView.showHint();
130 | return true;
131 | }
132 | });
133 | }
134 |
135 | private void setColorFilter(int position) {
136 | if (position == selectedPosition && ColorUtils.calculateLuminance(colors[position]) >= 0.65) {
137 | imageView.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
138 | } else {
139 | imageView.setColorFilter(null);
140 | }
141 | }
142 | }
143 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Color Picker
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Yet another open source color picker for Android. So, why should you use this color picker? It is highly customizable and easy to use. You can simply add the `ColorPreference` to your preferences and a beautiful color picker dialog will be displayed without additional code. The color picker supports alpha and allows you to set your own presets.
12 |
13 | The original ColorPickerView was written by [Daniel Nilsson](https://github.com/danielnilsson9/color-picker-view).
14 |
15 | ## Screenshots
16 | 
17 |
18 |
19 |
20 | ## Usage
21 |
22 | Add the `ColorPreference` to your preference XML:
23 |
24 | ```xml
25 |
27 |
28 |
29 |
30 |
35 |
36 | ...
37 |
38 |
39 |
40 |
41 | ```
42 |
43 | Note: Using AndroidX's `PreferenceFragmentCompat`? Then use `com.jaredrummler.android.colorpicker.ColorPreferenceCompat`
44 |
45 | You can add attributes to customize the `ColorPreference`:
46 |
47 | | name | type | documentation |
48 | |---------------------|-----------|---------------------------------------------------------------------------------------|
49 | | cpv_dialogType | enum | "custom" to show the color picker, "preset" to show pre-defined colors |
50 | | cpv_showAlphaSlider | boolean | Show a slider for changing the alpha of a color (adding transparency) |
51 | | cpv_colorShape | enum | "square" or "circle" for the shape of the color preview |
52 | | cpv_colorPresets | reference | An int-array of pre-defined colors to show in the dialog |
53 | | cpv_dialogTitle | reference | The string resource id for the dialog title. By default the title is "Select a Color" |
54 | | cpv_showColorShades | boolean | true to show different shades of the selected color |
55 | | cpv_allowPresets | boolean | true to add a button to toggle to the custom color picker |
56 | | cpv_allowCustom | boolean | true to add a button to toggle to the presets color picker |
57 | | cpv_showDialog | boolean | true to let the ColorPreference handle showing the dialog |
58 |
59 | You can also show a `ColorPickerDialog` without using the `ColorPreference`:
60 |
61 | ```java
62 | ColorPickerDialog.newBuilder().setColor(color).show(activity);
63 | ```
64 |
65 | All the attributes above can also be applied to the `ColorPickerDialog`. The activity that shows the dialog *must*
66 | implement `ColorPickerDialogListener` to get a callback when a color is selected.
67 |
68 | For further doumentation about how to use the library, check the [demo](demo) app included in this project.
69 |
70 | ## Download
71 |
72 | Download [the latest AAR](https://repo1.maven.org/maven2/com/jaredrummler/colorpicker/1.1.0/colorpicker-1.1.0.aar) or grab via Gradle:
73 |
74 | ```groovy
75 | implementation 'com.jaredrummler:colorpicker:1.1.0'
76 | ```
77 |
78 | ---
79 |
80 | ## v7 Preference Support Library
81 |
82 | If you are using the v7 Preference Support Library you should use this in your `build.gradle` instead:
83 |
84 | ```groovy
85 | implementation 'com.jaredrummler:colorpicker-compat:1.0.5'
86 | ```
87 |
88 | Note: The demo project uses the v7 Preference Support Library
89 |
90 | ## License
91 |
92 | Licensed under the Apache License, Version 2.0 (the "License");
93 | you may not use this file except in compliance with the License.
94 | You may obtain a copy of the License at
95 |
96 | http://www.apache.org/licenses/LICENSE-2.0
97 |
98 | Unless required by applicable law or agreed to in writing, software
99 | distributed under the License is distributed on an "AS IS" BASIS,
100 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
101 | See the License for the specific language governing permissions and
102 | limitations under the License.
103 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreferenceCompat.java:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.android.colorpicker;
2 |
3 | import android.content.Context;
4 | import android.content.ContextWrapper;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Color;
7 | import android.util.AttributeSet;
8 | import androidx.annotation.ColorInt;
9 | import androidx.annotation.NonNull;
10 | import androidx.fragment.app.FragmentActivity;
11 | import androidx.preference.Preference;
12 | import androidx.preference.PreferenceViewHolder;
13 |
14 | /**
15 | * A Preference to select a color
16 | */
17 | public class ColorPreferenceCompat extends Preference implements ColorPickerDialogListener {
18 |
19 | private static final int SIZE_NORMAL = 0;
20 | private static final int SIZE_LARGE = 1;
21 |
22 | private OnShowDialogListener onShowDialogListener;
23 | private int color = Color.BLACK;
24 | private boolean showDialog;
25 | @ColorPickerDialog.DialogType private int dialogType;
26 | private int colorShape;
27 | private boolean allowPresets;
28 | private boolean allowCustom;
29 | private boolean showAlphaSlider;
30 | private boolean showColorShades;
31 | private int previewSize;
32 | private int[] presets;
33 | private int dialogTitle;
34 | private int defaultColor;
35 |
36 | public ColorPreferenceCompat(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | init(attrs);
39 | }
40 |
41 | public ColorPreferenceCompat(Context context, AttributeSet attrs, int defStyle) {
42 | super(context, attrs, defStyle);
43 | init(attrs);
44 | }
45 |
46 | private void init(AttributeSet attrs) {
47 | setPersistent(true);
48 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference);
49 | showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true);
50 | //noinspection WrongConstant
51 | dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS);
52 | colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE);
53 | allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true);
54 | allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true);
55 | showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false);
56 | showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true);
57 | previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL);
58 | final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0);
59 | dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title);
60 | if (presetsResId != 0) {
61 | presets = getContext().getResources().getIntArray(presetsResId);
62 | } else {
63 | presets = ColorPickerDialog.MATERIAL_COLORS;
64 | }
65 | if (colorShape == ColorShape.CIRCLE) {
66 | setWidgetLayoutResource(
67 | previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle);
68 | } else {
69 | setWidgetLayoutResource(
70 | previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square);
71 | }
72 | a.recycle();
73 | }
74 |
75 | @Override protected void onClick() {
76 | super.onClick();
77 | if (onShowDialogListener != null) {
78 | onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color);
79 | } else if (showDialog) {
80 | ColorPickerDialog dialog = ColorPickerDialog.newBuilder()
81 | .setDialogType(dialogType)
82 | .setDialogTitle(dialogTitle)
83 | .setColorShape(colorShape)
84 | .setPresets(presets)
85 | .setAllowPresets(allowPresets)
86 | .setAllowCustom(allowCustom)
87 | .setShowAlphaSlider(showAlphaSlider)
88 | .setShowColorShades(showColorShades)
89 | .setColor(color)
90 | .create();
91 | dialog.setColorPickerDialogListener(this);
92 | getActivity().getSupportFragmentManager()
93 | .beginTransaction()
94 | .add(dialog, getFragmentTag())
95 | .commitAllowingStateLoss();
96 | }
97 | }
98 |
99 | public FragmentActivity getActivity() {
100 | Context context = getContext();
101 | if (context instanceof FragmentActivity) {
102 | return (FragmentActivity) context;
103 | } else if (context instanceof ContextWrapper) {
104 | Context baseContext = ((ContextWrapper) context).getBaseContext();
105 | if (baseContext instanceof FragmentActivity) {
106 | return (FragmentActivity) baseContext;
107 | }
108 | }
109 | throw new IllegalStateException("Error getting activity from context");
110 | }
111 |
112 | @Override public void onAttached() {
113 | super.onAttached();
114 | if (showDialog) {
115 | ColorPickerDialog fragment =
116 | (ColorPickerDialog) getActivity().getSupportFragmentManager().findFragmentByTag(getFragmentTag());
117 | if (fragment != null) {
118 | // re-bind preference to fragment
119 | fragment.setColorPickerDialogListener(this);
120 | }
121 | }
122 | }
123 |
124 | @Override public void onBindViewHolder(PreferenceViewHolder holder) {
125 | super.onBindViewHolder(holder);
126 | ColorPanelView preview = (ColorPanelView) holder.itemView.findViewById(R.id.cpv_preference_preview_color_panel);
127 | if (preview != null) {
128 | preview.setColor(color);
129 | }
130 | }
131 |
132 | @Override protected void onSetInitialValue(Object defaultValue) {
133 | super.onSetInitialValue(defaultValue);
134 | if (defaultValue instanceof Integer) {
135 | color = (Integer) defaultValue;
136 | persistInt(color);
137 | } else {
138 | color = getPersistedInt(0xFF000000);
139 | }
140 | }
141 |
142 | @Override protected Object onGetDefaultValue(TypedArray a, int index) {
143 | defaultColor = a.getInteger(index, Color.BLACK);
144 | return defaultColor;
145 | }
146 |
147 | @Override
148 | public void setDefaultValue(Object defaultValue) {
149 | super.setDefaultValue(defaultValue);
150 | defaultColor = Integer.parseInt(defaultValue.toString());
151 | }
152 |
153 | @Override public void onColorSelected(int dialogId, @ColorInt int color) {
154 | saveValue(color);
155 | }
156 |
157 | @Override
158 | public void onColorReset(int dialogId) {
159 | saveValue(defaultColor);
160 | }
161 |
162 | @Override public void onDialogDismissed(int dialogId) {
163 | // no-op
164 | }
165 |
166 | /**
167 | * Set the new color
168 | *
169 | * @param color The newly selected color
170 | */
171 | public void saveValue(@ColorInt int color) {
172 | this.color = color;
173 | persistInt(this.color);
174 | notifyChanged();
175 | callChangeListener(color);
176 | }
177 |
178 | /**
179 | * Get the colors that will be shown in the {@link ColorPickerDialog}.
180 | *
181 | * @return An array of color ints
182 | */
183 | public int[] getPresets() {
184 | return presets;
185 | }
186 |
187 | /**
188 | * Set the colors shown in the {@link ColorPickerDialog}.
189 | *
190 | * @param presets An array of color ints
191 | */
192 | public void setPresets(@NonNull int[] presets) {
193 | this.presets = presets;
194 | }
195 |
196 | /**
197 | * The listener used for showing the {@link ColorPickerDialog}.
198 | * Call {@link #saveValue(int)} after the user chooses a color.
199 | * If this is set then it is up to you to show the dialog.
200 | *
201 | * @param listener The listener to show the dialog
202 | */
203 | public void setOnShowDialogListener(OnShowDialogListener listener) {
204 | onShowDialogListener = listener;
205 | }
206 |
207 | /**
208 | * The tag used for the {@link ColorPickerDialog}.
209 | *
210 | * @return The tag
211 | */
212 | public String getFragmentTag() {
213 | return "color_" + getKey();
214 | }
215 |
216 | public interface OnShowDialogListener {
217 |
218 | void onShowColorPickerDialog(String title, int currentColor);
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Color;
22 | import android.preference.Preference;
23 | import android.util.AttributeSet;
24 | import android.view.View;
25 | import androidx.annotation.ColorInt;
26 | import androidx.annotation.NonNull;
27 | import androidx.fragment.app.FragmentActivity;
28 |
29 | /**
30 | * A Preference to select a color
31 | */
32 | public class ColorPreference extends Preference implements ColorPickerDialogListener {
33 |
34 | private static final int SIZE_NORMAL = 0;
35 | private static final int SIZE_LARGE = 1;
36 |
37 | private OnShowDialogListener onShowDialogListener;
38 | private int color = Color.BLACK;
39 | private boolean showDialog;
40 | @ColorPickerDialog.DialogType private int dialogType;
41 | private int colorShape;
42 | private boolean allowPresets;
43 | private boolean allowCustom;
44 | private boolean showAlphaSlider;
45 | private boolean showColorShades;
46 | private int previewSize;
47 | private int[] presets;
48 | private int dialogTitle;
49 | private int defaultColor;
50 |
51 | public ColorPreference(Context context, AttributeSet attrs) {
52 | super(context, attrs);
53 | init(attrs);
54 | }
55 |
56 | public ColorPreference(Context context, AttributeSet attrs, int defStyle) {
57 | super(context, attrs, defStyle);
58 | init(attrs);
59 | }
60 |
61 | private void init(AttributeSet attrs) {
62 | setPersistent(true);
63 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference);
64 | showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true);
65 | //noinspection WrongConstant
66 | dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS);
67 | colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE);
68 | allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true);
69 | allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true);
70 | showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false);
71 | showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true);
72 | previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL);
73 | final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0);
74 | dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title);
75 | if (presetsResId != 0) {
76 | presets = getContext().getResources().getIntArray(presetsResId);
77 | } else {
78 | presets = ColorPickerDialog.MATERIAL_COLORS;
79 | }
80 | if (colorShape == ColorShape.CIRCLE) {
81 | setWidgetLayoutResource(
82 | previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle);
83 | } else {
84 | setWidgetLayoutResource(
85 | previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square);
86 | }
87 | a.recycle();
88 | }
89 |
90 | @Override protected void onClick() {
91 | super.onClick();
92 | if (onShowDialogListener != null) {
93 | onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color);
94 | } else if (showDialog) {
95 | ColorPickerDialog dialog = ColorPickerDialog.newBuilder()
96 | .setDialogType(dialogType)
97 | .setDialogTitle(dialogTitle)
98 | .setColorShape(colorShape)
99 | .setPresets(presets)
100 | .setAllowPresets(allowPresets)
101 | .setAllowCustom(allowCustom)
102 | .setShowAlphaSlider(showAlphaSlider)
103 | .setShowColorShades(showColorShades)
104 | .setColor(color)
105 | .create();
106 | dialog.setColorPickerDialogListener(this);
107 | FragmentActivity activity = (FragmentActivity) getContext();
108 | activity.getSupportFragmentManager()
109 | .beginTransaction()
110 | .add(dialog, getFragmentTag())
111 | .commitAllowingStateLoss();
112 | }
113 | }
114 |
115 | @Override protected void onAttachedToActivity() {
116 | super.onAttachedToActivity();
117 |
118 | if (showDialog) {
119 | FragmentActivity activity = (FragmentActivity) getContext();
120 | ColorPickerDialog fragment =
121 | (ColorPickerDialog) activity.getSupportFragmentManager().findFragmentByTag(getFragmentTag());
122 | if (fragment != null) {
123 | // re-bind preference to fragment
124 | fragment.setColorPickerDialogListener(this);
125 | }
126 | }
127 | }
128 |
129 | @Override protected void onBindView(View view) {
130 | super.onBindView(view);
131 | ColorPanelView preview = (ColorPanelView) view.findViewById(R.id.cpv_preference_preview_color_panel);
132 | if (preview != null) {
133 | preview.setColor(color);
134 | }
135 | }
136 |
137 | @Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
138 | if (restorePersistedValue) {
139 | color = getPersistedInt(0xFF000000);
140 | } else {
141 | color = (Integer) defaultValue;
142 | persistInt(color);
143 | }
144 | }
145 |
146 | @Override protected Object onGetDefaultValue(TypedArray a, int index) {
147 | defaultColor = a.getInteger(index, Color.BLACK);
148 | return defaultColor;
149 | }
150 |
151 | @Override
152 | public void setDefaultValue(Object defaultValue) {
153 | super.setDefaultValue(defaultValue);
154 | defaultColor = Integer.parseInt(defaultValue.toString());
155 | }
156 |
157 | @Override public void onColorSelected(int dialogId, @ColorInt int color) {
158 | saveValue(color);
159 | }
160 |
161 | @Override public void onDialogDismissed(int dialogId) {
162 | // no-op
163 | }
164 |
165 | @Override public void onColorReset(int dialogId) {
166 | saveValue(defaultColor);
167 | }
168 |
169 | /**
170 | * Set the new color
171 | *
172 | * @param color The newly selected color
173 | */
174 | public void saveValue(@ColorInt int color) {
175 | this.color = color;
176 | persistInt(this.color);
177 | notifyChanged();
178 | callChangeListener(color);
179 | }
180 |
181 | /**
182 | * Get the colors that will be shown in the {@link ColorPickerDialog}.
183 | *
184 | * @return An array of color ints
185 | */
186 | public int[] getPresets() {
187 | return presets;
188 | }
189 |
190 | /**
191 | * Set the colors shown in the {@link ColorPickerDialog}.
192 | *
193 | * @param presets An array of color ints
194 | */
195 | public void setPresets(@NonNull int[] presets) {
196 | this.presets = presets;
197 | }
198 |
199 | /**
200 | * The listener used for showing the {@link ColorPickerDialog}.
201 | * Call {@link #saveValue(int)} after the user chooses a color.
202 | * If this is set then it is up to you to show the dialog.
203 | *
204 | * @param listener The listener to show the dialog
205 | */
206 | public void setOnShowDialogListener(OnShowDialogListener listener) {
207 | onShowDialogListener = listener;
208 | }
209 |
210 | /**
211 | * The tag used for the {@link ColorPickerDialog}.
212 | *
213 | * @return The tag
214 | */
215 | public String getFragmentTag() {
216 | return "color_" + getKey();
217 | }
218 |
219 | public interface OnShowDialogListener {
220 |
221 | void onShowColorPickerDialog(String title, int currentColor);
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPanelView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Bitmap;
22 | import android.graphics.BitmapShader;
23 | import android.graphics.Canvas;
24 | import android.graphics.Color;
25 | import android.graphics.Paint;
26 | import android.graphics.Rect;
27 | import android.graphics.RectF;
28 | import android.graphics.Shader;
29 | import android.graphics.drawable.BitmapDrawable;
30 | import android.graphics.drawable.Drawable;
31 | import android.os.Bundle;
32 | import android.os.Parcelable;
33 | import android.util.AttributeSet;
34 | import android.util.TypedValue;
35 | import android.view.Gravity;
36 | import android.view.View;
37 | import android.widget.Toast;
38 | import androidx.annotation.ColorInt;
39 | import androidx.core.view.GravityCompat;
40 | import androidx.core.view.ViewCompat;
41 | import java.util.Locale;
42 |
43 | /**
44 | * This class draws a panel which which will be filled with a color which can be set. It can be used to show the
45 | * currently selected color which you will get from the {@link ColorPickerView}.
46 | */
47 | public class ColorPanelView extends View {
48 |
49 | private final static int DEFAULT_BORDER_COLOR = 0xFF6E6E6E;
50 |
51 | private Drawable alphaPattern;
52 | private Paint borderPaint;
53 | private Paint colorPaint;
54 | private Paint alphaPaint;
55 | private Paint originalPaint;
56 | private Rect drawingRect;
57 | private Rect colorRect;
58 | private RectF centerRect = new RectF();
59 | private boolean showOldColor;
60 |
61 | /* The width in pixels of the border surrounding the color panel. */
62 | private int borderWidthPx;
63 | private int borderColor = DEFAULT_BORDER_COLOR;
64 | private int color = Color.BLACK;
65 | private int shape;
66 |
67 | public ColorPanelView(Context context) {
68 | this(context, null);
69 | }
70 |
71 | public ColorPanelView(Context context, AttributeSet attrs) {
72 | this(context, attrs, 0);
73 | }
74 |
75 | public ColorPanelView(Context context, AttributeSet attrs, int defStyle) {
76 | super(context, attrs, defStyle);
77 | init(context, attrs);
78 | }
79 |
80 | @Override public Parcelable onSaveInstanceState() {
81 | Bundle state = new Bundle();
82 | state.putParcelable("instanceState", super.onSaveInstanceState());
83 | state.putInt("color", color);
84 | return state;
85 | }
86 |
87 | @Override public void onRestoreInstanceState(Parcelable state) {
88 | if (state instanceof Bundle) {
89 | Bundle bundle = (Bundle) state;
90 | color = bundle.getInt("color");
91 | state = bundle.getParcelable("instanceState");
92 | }
93 | super.onRestoreInstanceState(state);
94 | }
95 |
96 | private void init(Context context, AttributeSet attrs) {
97 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPanelView);
98 | shape = a.getInt(R.styleable.ColorPanelView_cpv_colorShape, ColorShape.CIRCLE);
99 | showOldColor = a.getBoolean(R.styleable.ColorPanelView_cpv_showOldColor, false);
100 | if (showOldColor && shape != ColorShape.CIRCLE) {
101 | throw new IllegalStateException("Color preview is only available in circle mode");
102 | }
103 | borderColor = a.getColor(R.styleable.ColorPanelView_cpv_borderColor, DEFAULT_BORDER_COLOR);
104 | a.recycle();
105 | if (borderColor == DEFAULT_BORDER_COLOR) {
106 | // If no specific border color has been set we take the default secondary text color as border/slider color.
107 | // Thus it will adopt to theme changes automatically.
108 | final TypedValue value = new TypedValue();
109 | TypedArray typedArray =
110 | context.obtainStyledAttributes(value.data, new int[] { android.R.attr.textColorSecondary });
111 | borderColor = typedArray.getColor(0, borderColor);
112 | typedArray.recycle();
113 | }
114 | borderWidthPx = DrawingUtils.dpToPx(context, 1);
115 | borderPaint = new Paint();
116 | borderPaint.setAntiAlias(true);
117 | colorPaint = new Paint();
118 | colorPaint.setAntiAlias(true);
119 | if (showOldColor) {
120 | originalPaint = new Paint();
121 | }
122 | if (shape == ColorShape.CIRCLE) {
123 | Bitmap bitmap = ((BitmapDrawable) context.getResources().getDrawable(R.drawable.cpv_alpha)).getBitmap();
124 | alphaPaint = new Paint();
125 | alphaPaint.setAntiAlias(true);
126 | BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
127 | alphaPaint.setShader(shader);
128 | }
129 | }
130 |
131 | @Override protected void onDraw(Canvas canvas) {
132 | borderPaint.setColor(borderColor);
133 | colorPaint.setColor(color);
134 | if (shape == ColorShape.SQUARE) {
135 | if (borderWidthPx > 0) {
136 | canvas.drawRect(drawingRect, borderPaint);
137 | }
138 | if (alphaPattern != null) {
139 | alphaPattern.draw(canvas);
140 | }
141 | canvas.drawRect(colorRect, colorPaint);
142 | } else if (shape == ColorShape.CIRCLE) {
143 | final int outerRadius = getMeasuredWidth() / 2;
144 | if (borderWidthPx > 0) {
145 | canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius, borderPaint);
146 | }
147 | if (Color.alpha(color) < 255) {
148 | canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, alphaPaint);
149 | }
150 | if (showOldColor) {
151 | canvas.drawArc(centerRect, 90, 180, true, originalPaint);
152 | canvas.drawArc(centerRect, 270, 180, true, colorPaint);
153 | } else {
154 | canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, colorPaint);
155 | }
156 | }
157 | }
158 |
159 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
160 | if (shape == ColorShape.SQUARE) {
161 | int width = MeasureSpec.getSize(widthMeasureSpec);
162 | int height = MeasureSpec.getSize(heightMeasureSpec);
163 | setMeasuredDimension(width, height);
164 | } else if (shape == ColorShape.CIRCLE) {
165 | super.onMeasure(widthMeasureSpec, widthMeasureSpec);
166 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
167 | } else {
168 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
169 | }
170 | }
171 |
172 | @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
173 | super.onSizeChanged(w, h, oldw, oldh);
174 | if (shape == ColorShape.SQUARE || showOldColor) {
175 | drawingRect = new Rect();
176 | drawingRect.left = getPaddingLeft();
177 | drawingRect.right = w - getPaddingRight();
178 | drawingRect.top = getPaddingTop();
179 | drawingRect.bottom = h - getPaddingBottom();
180 | if (showOldColor) {
181 | setUpCenterRect();
182 | } else {
183 | setUpColorRect();
184 | }
185 | }
186 | }
187 |
188 | private void setUpCenterRect() {
189 | final Rect dRect = drawingRect;
190 | int left = dRect.left + borderWidthPx;
191 | int top = dRect.top + borderWidthPx;
192 | int bottom = dRect.bottom - borderWidthPx;
193 | int right = dRect.right - borderWidthPx;
194 | centerRect = new RectF(left, top, right, bottom);
195 | }
196 |
197 | private void setUpColorRect() {
198 | final Rect dRect = drawingRect;
199 | int left = dRect.left + borderWidthPx;
200 | int top = dRect.top + borderWidthPx;
201 | int bottom = dRect.bottom - borderWidthPx;
202 | int right = dRect.right - borderWidthPx;
203 | colorRect = new Rect(left, top, right, bottom);
204 | alphaPattern = new AlphaPatternDrawable(DrawingUtils.dpToPx(getContext(), 4));
205 | alphaPattern.setBounds(Math.round(colorRect.left), Math.round(colorRect.top), Math.round(colorRect.right),
206 | Math.round(colorRect.bottom));
207 | }
208 |
209 | /**
210 | * Get the color currently show by this view.
211 | *
212 | * @return the color value
213 | */
214 | public int getColor() {
215 | return color;
216 | }
217 |
218 | /**
219 | * Set the color that should be shown by this view.
220 | *
221 | * @param color the color value
222 | */
223 | public void setColor(int color) {
224 | this.color = color;
225 | invalidate();
226 | }
227 |
228 | /**
229 | * Set the original color. This is only used for previewing colors.
230 | *
231 | * @param color The original color
232 | */
233 | public void setOriginalColor(@ColorInt int color) {
234 | if (originalPaint != null) {
235 | originalPaint.setColor(color);
236 | }
237 | }
238 |
239 | /**
240 | * @return the color of the border surrounding the panel.
241 | */
242 | public int getBorderColor() {
243 | return borderColor;
244 | }
245 |
246 | /**
247 | * Set the color of the border surrounding the panel.
248 | *
249 | * @param color the color value
250 | */
251 | public void setBorderColor(int color) {
252 | borderColor = color;
253 | invalidate();
254 | }
255 |
256 | /**
257 | * Get the shape
258 | *
259 | * @return Either {@link ColorShape#SQUARE} or {@link ColorShape#CIRCLE}.
260 | */
261 | @ColorShape public int getShape() {
262 | return shape;
263 | }
264 |
265 | /**
266 | * Set the shape.
267 | *
268 | * @param shape Either {@link ColorShape#SQUARE} or {@link ColorShape#CIRCLE}.
269 | */
270 | public void setShape(@ColorShape int shape) {
271 | this.shape = shape;
272 | invalidate();
273 | }
274 |
275 | /**
276 | * Show a toast message with the hex color code below the view.
277 | */
278 | public void showHint() {
279 | final int[] screenPos = new int[2];
280 | final Rect displayFrame = new Rect();
281 | getLocationOnScreen(screenPos);
282 | getWindowVisibleDisplayFrame(displayFrame);
283 | final Context context = getContext();
284 | final int width = getWidth();
285 | final int height = getHeight();
286 | final int midy = screenPos[1] + height / 2;
287 | int referenceX = screenPos[0] + width / 2;
288 | if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR) {
289 | final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
290 | referenceX = screenWidth - referenceX; // mirror
291 | }
292 | StringBuilder hint = new StringBuilder("#");
293 | if (Color.alpha(color) != 255) {
294 | hint.append(Integer.toHexString(color).toUpperCase(Locale.ENGLISH));
295 | } else {
296 | hint.append(String.format("%06X", 0xFFFFFF & color).toUpperCase(Locale.ENGLISH));
297 | }
298 | Toast cheatSheet = Toast.makeText(context, hint.toString(), Toast.LENGTH_SHORT);
299 | if (midy < displayFrame.height()) {
300 | // Show along the top; follow action buttons
301 | cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX, screenPos[1] + height - displayFrame.top);
302 | } else {
303 | // Show along the bottom center
304 | cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
305 | }
306 | cheatSheet.show();
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/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 2016 Jared Rummler
190 | Copyright 2015 Daniel Nilsson
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.android.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Bitmap;
22 | import android.graphics.Bitmap.Config;
23 | import android.graphics.Canvas;
24 | import android.graphics.Color;
25 | import android.graphics.ComposeShader;
26 | import android.graphics.LinearGradient;
27 | import android.graphics.Paint;
28 | import android.graphics.Paint.Align;
29 | import android.graphics.Paint.Style;
30 | import android.graphics.Point;
31 | import android.graphics.PorterDuff;
32 | import android.graphics.Rect;
33 | import android.graphics.RectF;
34 | import android.graphics.Shader;
35 | import android.graphics.Shader.TileMode;
36 | import android.os.Bundle;
37 | import android.os.Parcelable;
38 | import android.util.AttributeSet;
39 | import android.util.TypedValue;
40 | import android.view.MotionEvent;
41 | import android.view.View;
42 |
43 | /**
44 | * Displays a color picker to the user and allow them to select a color. A slider for the alpha channel is also
45 | * available.
46 | * Enable it by setting setAlphaSliderVisible(boolean) to true.
47 | */
48 | public class ColorPickerView extends View {
49 |
50 | private final static int DEFAULT_BORDER_COLOR = 0xFF6E6E6E;
51 | private final static int DEFAULT_SLIDER_COLOR = 0xFFBDBDBD;
52 |
53 | private final static int HUE_PANEL_WDITH_DP = 30;
54 | private final static int ALPHA_PANEL_HEIGH_DP = 20;
55 | private final static int PANEL_SPACING_DP = 10;
56 | private final static int CIRCLE_TRACKER_RADIUS_DP = 5;
57 | private final static int SLIDER_TRACKER_SIZE_DP = 4;
58 | private final static int SLIDER_TRACKER_OFFSET_DP = 2;
59 |
60 | /**
61 | * The width in pixels of the border
62 | * surrounding all color panels.
63 | */
64 | private final static int BORDER_WIDTH_PX = 1;
65 |
66 | /**
67 | * The width in px of the hue panel.
68 | */
69 | private int huePanelWidthPx;
70 | /**
71 | * The height in px of the alpha panel
72 | */
73 | private int alphaPanelHeightPx;
74 | /**
75 | * The distance in px between the different
76 | * color panels.
77 | */
78 | private int panelSpacingPx;
79 | /**
80 | * The radius in px of the color palette tracker circle.
81 | */
82 | private int circleTrackerRadiusPx;
83 | /**
84 | * The px which the tracker of the hue or alpha panel
85 | * will extend outside of its bounds.
86 | */
87 | private int sliderTrackerOffsetPx;
88 | /**
89 | * Height of slider tracker on hue panel,
90 | * width of slider on alpha panel.
91 | */
92 | private int sliderTrackerSizePx;
93 |
94 | private Paint satValPaint;
95 | private Paint satValTrackerPaint;
96 |
97 | private Paint alphaPaint;
98 | private Paint alphaTextPaint;
99 | private Paint hueAlphaTrackerPaint;
100 |
101 | private Paint borderPaint;
102 |
103 | private Shader valShader;
104 | private Shader satShader;
105 | private Shader alphaShader;
106 |
107 | /*
108 | * We cache a bitmap of the sat/val panel which is expensive to draw each time.
109 | * We can reuse it when the user is sliding the circle picker as long as the hue isn't changed.
110 | */
111 | private BitmapCache satValBackgroundCache;
112 | /* We cache the hue background to since its also very expensive now. */
113 | private BitmapCache hueBackgroundCache;
114 |
115 | /* Current values */
116 | private int alpha = 0xff;
117 | private float hue = 360f;
118 | private float sat = 0f;
119 | private float val = 0f;
120 |
121 | private boolean showAlphaPanel = false;
122 | private String alphaSliderText = null;
123 | private int sliderTrackerColor = DEFAULT_SLIDER_COLOR;
124 | private int borderColor = DEFAULT_BORDER_COLOR;
125 |
126 | /**
127 | * Minimum required padding. The offset from the
128 | * edge we must have or else the finger tracker will
129 | * get clipped when it's drawn outside of the view.
130 | */
131 | private int mRequiredPadding;
132 |
133 | /**
134 | * The Rect in which we are allowed to draw.
135 | * Trackers can extend outside slightly,
136 | * due to the required padding we have set.
137 | */
138 | private Rect drawingRect;
139 |
140 | private Rect satValRect;
141 | private Rect hueRect;
142 | private Rect alphaRect;
143 |
144 | private Point startTouchPoint = null;
145 |
146 | private AlphaPatternDrawable alphaPatternDrawable;
147 | private OnColorChangedListener onColorChangedListener;
148 |
149 | public ColorPickerView(Context context) {
150 | this(context, null);
151 | }
152 |
153 | public ColorPickerView(Context context, AttributeSet attrs) {
154 | this(context, attrs, 0);
155 | }
156 |
157 | public ColorPickerView(Context context, AttributeSet attrs, int defStyle) {
158 | super(context, attrs, defStyle);
159 | init(context, attrs);
160 | }
161 |
162 | @Override public Parcelable onSaveInstanceState() {
163 | Bundle state = new Bundle();
164 | state.putParcelable("instanceState", super.onSaveInstanceState());
165 | state.putInt("alpha", alpha);
166 | state.putFloat("hue", hue);
167 | state.putFloat("sat", sat);
168 | state.putFloat("val", val);
169 | state.putBoolean("show_alpha", showAlphaPanel);
170 | state.putString("alpha_text", alphaSliderText);
171 |
172 | return state;
173 | }
174 |
175 | @Override public void onRestoreInstanceState(Parcelable state) {
176 |
177 | if (state instanceof Bundle) {
178 | Bundle bundle = (Bundle) state;
179 |
180 | alpha = bundle.getInt("alpha");
181 | hue = bundle.getFloat("hue");
182 | sat = bundle.getFloat("sat");
183 | val = bundle.getFloat("val");
184 | showAlphaPanel = bundle.getBoolean("show_alpha");
185 | alphaSliderText = bundle.getString("alpha_text");
186 |
187 | state = bundle.getParcelable("instanceState");
188 | }
189 | super.onRestoreInstanceState(state);
190 | }
191 |
192 | private void init(Context context, AttributeSet attrs) {
193 | //Load those if set in xml resource file.
194 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPickerView);
195 | showAlphaPanel = a.getBoolean(R.styleable.ColorPickerView_cpv_alphaChannelVisible, false);
196 | alphaSliderText = a.getString(R.styleable.ColorPickerView_cpv_alphaChannelText);
197 | sliderTrackerColor = a.getColor(R.styleable.ColorPickerView_cpv_sliderColor, 0xFFBDBDBD);
198 | borderColor = a.getColor(R.styleable.ColorPickerView_cpv_borderColor, 0xFF6E6E6E);
199 | a.recycle();
200 |
201 | applyThemeColors(context);
202 |
203 | huePanelWidthPx = DrawingUtils.dpToPx(getContext(), HUE_PANEL_WDITH_DP);
204 | alphaPanelHeightPx = DrawingUtils.dpToPx(getContext(), ALPHA_PANEL_HEIGH_DP);
205 | panelSpacingPx = DrawingUtils.dpToPx(getContext(), PANEL_SPACING_DP);
206 | circleTrackerRadiusPx = DrawingUtils.dpToPx(getContext(), CIRCLE_TRACKER_RADIUS_DP);
207 | sliderTrackerSizePx = DrawingUtils.dpToPx(getContext(), SLIDER_TRACKER_SIZE_DP);
208 | sliderTrackerOffsetPx = DrawingUtils.dpToPx(getContext(), SLIDER_TRACKER_OFFSET_DP);
209 |
210 | mRequiredPadding = getResources().getDimensionPixelSize(R.dimen.cpv_required_padding);
211 |
212 | initPaintTools();
213 |
214 | //Needed for receiving trackball motion events.
215 | setFocusable(true);
216 | setFocusableInTouchMode(true);
217 | }
218 |
219 | private void applyThemeColors(Context c) {
220 | // If no specific border/slider color has been
221 | // set we take the default secondary text color
222 | // as border/slider color. Thus it will adopt
223 | // to theme changes automatically.
224 |
225 | final TypedValue value = new TypedValue();
226 | TypedArray a = c.obtainStyledAttributes(value.data, new int[] { android.R.attr.textColorSecondary });
227 |
228 | if (borderColor == DEFAULT_BORDER_COLOR) {
229 | borderColor = a.getColor(0, DEFAULT_BORDER_COLOR);
230 | }
231 |
232 | if (sliderTrackerColor == DEFAULT_SLIDER_COLOR) {
233 | sliderTrackerColor = a.getColor(0, DEFAULT_SLIDER_COLOR);
234 | }
235 |
236 | a.recycle();
237 | }
238 |
239 | private void initPaintTools() {
240 |
241 | satValPaint = new Paint();
242 | satValTrackerPaint = new Paint();
243 | hueAlphaTrackerPaint = new Paint();
244 | alphaPaint = new Paint();
245 | alphaTextPaint = new Paint();
246 | borderPaint = new Paint();
247 |
248 | satValTrackerPaint.setStyle(Style.STROKE);
249 | satValTrackerPaint.setStrokeWidth(DrawingUtils.dpToPx(getContext(), 2));
250 | satValTrackerPaint.setAntiAlias(true);
251 |
252 | hueAlphaTrackerPaint.setColor(sliderTrackerColor);
253 | hueAlphaTrackerPaint.setStyle(Style.STROKE);
254 | hueAlphaTrackerPaint.setStrokeWidth(DrawingUtils.dpToPx(getContext(), 2));
255 | hueAlphaTrackerPaint.setAntiAlias(true);
256 |
257 | alphaTextPaint.setColor(0xff1c1c1c);
258 | alphaTextPaint.setTextSize(DrawingUtils.dpToPx(getContext(), 14));
259 | alphaTextPaint.setAntiAlias(true);
260 | alphaTextPaint.setTextAlign(Align.CENTER);
261 | alphaTextPaint.setFakeBoldText(true);
262 | }
263 |
264 | @Override protected void onDraw(Canvas canvas) {
265 | if (drawingRect.width() <= 0 || drawingRect.height() <= 0) {
266 | return;
267 | }
268 |
269 | drawSatValPanel(canvas);
270 | drawHuePanel(canvas);
271 | drawAlphaPanel(canvas);
272 | }
273 |
274 | private void drawSatValPanel(Canvas canvas) {
275 | final Rect rect = satValRect;
276 |
277 | if (BORDER_WIDTH_PX > 0) {
278 | borderPaint.setColor(borderColor);
279 | canvas.drawRect(drawingRect.left, drawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX,
280 | borderPaint);
281 | }
282 |
283 | if (valShader == null) {
284 | //Black gradient has either not been created or the view has been resized.
285 | valShader =
286 | new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, 0xffffffff, 0xff000000, TileMode.CLAMP);
287 | }
288 |
289 | //If the hue has changed we need to recreate the cache.
290 | if (satValBackgroundCache == null || satValBackgroundCache.value != hue) {
291 |
292 | if (satValBackgroundCache == null) {
293 | satValBackgroundCache = new BitmapCache();
294 | }
295 |
296 | //We create our bitmap in the cache if it doesn't exist.
297 | if (satValBackgroundCache.bitmap == null) {
298 | satValBackgroundCache.bitmap = Bitmap.createBitmap(rect.width(), rect.height(), Config.ARGB_8888);
299 | }
300 |
301 | //We create the canvas once so we can draw on our bitmap and the hold on to it.
302 | if (satValBackgroundCache.canvas == null) {
303 | satValBackgroundCache.canvas = new Canvas(satValBackgroundCache.bitmap);
304 | }
305 |
306 | int rgb = Color.HSVToColor(new float[] { hue, 1f, 1f });
307 |
308 | satShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, 0xffffffff, rgb, TileMode.CLAMP);
309 |
310 | ComposeShader mShader = new ComposeShader(valShader, satShader, PorterDuff.Mode.MULTIPLY);
311 | satValPaint.setShader(mShader);
312 |
313 | // Finally we draw on our canvas, the result will be
314 | // stored in our bitmap which is already in the cache.
315 | // Since this is drawn on a canvas not rendered on
316 | // screen it will automatically not be using the
317 | // hardware acceleration. And this was the code that
318 | // wasn't supported by hardware acceleration which mean
319 | // there is no need to turn it of anymore. The rest of
320 | // the view will still be hw accelerated.
321 | satValBackgroundCache.canvas.drawRect(0, 0, satValBackgroundCache.bitmap.getWidth(),
322 | satValBackgroundCache.bitmap.getHeight(), satValPaint);
323 |
324 | //We set the hue value in our cache to which hue it was drawn with,
325 | //then we know that if it hasn't changed we can reuse our cached bitmap.
326 | satValBackgroundCache.value = hue;
327 | }
328 |
329 | // We draw our bitmap from the cached, if the hue has changed
330 | // then it was just recreated otherwise the old one will be used.
331 | canvas.drawBitmap(satValBackgroundCache.bitmap, null, rect, null);
332 |
333 | Point p = satValToPoint(sat, val);
334 |
335 | satValTrackerPaint.setColor(0xff000000);
336 | canvas.drawCircle(p.x, p.y, circleTrackerRadiusPx - DrawingUtils.dpToPx(getContext(), 1), satValTrackerPaint);
337 |
338 | satValTrackerPaint.setColor(0xffdddddd);
339 | canvas.drawCircle(p.x, p.y, circleTrackerRadiusPx, satValTrackerPaint);
340 | }
341 |
342 | private void drawHuePanel(Canvas canvas) {
343 | final Rect rect = hueRect;
344 |
345 | if (BORDER_WIDTH_PX > 0) {
346 | borderPaint.setColor(borderColor);
347 |
348 | canvas.drawRect(rect.left - BORDER_WIDTH_PX, rect.top - BORDER_WIDTH_PX, rect.right + BORDER_WIDTH_PX,
349 | rect.bottom + BORDER_WIDTH_PX, borderPaint);
350 | }
351 |
352 | if (hueBackgroundCache == null) {
353 | hueBackgroundCache = new BitmapCache();
354 | hueBackgroundCache.bitmap = Bitmap.createBitmap(rect.width(), rect.height(), Config.ARGB_8888);
355 | hueBackgroundCache.canvas = new Canvas(hueBackgroundCache.bitmap);
356 |
357 | int[] hueColors = new int[(int) (rect.height() + 0.5f)];
358 |
359 | // Generate array of all colors, will be drawn as individual lines.
360 | float h = 360f;
361 | for (int i = 0; i < hueColors.length; i++) {
362 | hueColors[i] = Color.HSVToColor(new float[] { h, 1f, 1f });
363 | h -= 360f / hueColors.length;
364 | }
365 |
366 | // Time to draw the hue color gradient,
367 | // its drawn as individual lines which
368 | // will be quite many when the resolution is high
369 | // and/or the panel is large.
370 | Paint linePaint = new Paint();
371 | linePaint.setStrokeWidth(0);
372 | for (int i = 0; i < hueColors.length; i++) {
373 | linePaint.setColor(hueColors[i]);
374 | hueBackgroundCache.canvas.drawLine(0, i, hueBackgroundCache.bitmap.getWidth(), i, linePaint);
375 | }
376 | }
377 |
378 | canvas.drawBitmap(hueBackgroundCache.bitmap, null, rect, null);
379 |
380 | Point p = hueToPoint(hue);
381 |
382 | RectF r = new RectF();
383 | r.left = rect.left - sliderTrackerOffsetPx;
384 | r.right = rect.right + sliderTrackerOffsetPx;
385 | r.top = p.y - (sliderTrackerSizePx / 2);
386 | r.bottom = p.y + (sliderTrackerSizePx / 2);
387 |
388 | canvas.drawRoundRect(r, 2, 2, hueAlphaTrackerPaint);
389 | }
390 |
391 | private void drawAlphaPanel(Canvas canvas) {
392 | /*
393 | * Will be drawn with hw acceleration, very fast.
394 | * Also the AlphaPatternDrawable is backed by a bitmap
395 | * generated only once if the size does not change.
396 | */
397 |
398 | if (!showAlphaPanel || alphaRect == null || alphaPatternDrawable == null) return;
399 |
400 | final Rect rect = alphaRect;
401 |
402 | if (BORDER_WIDTH_PX > 0) {
403 | borderPaint.setColor(borderColor);
404 | canvas.drawRect(rect.left - BORDER_WIDTH_PX, rect.top - BORDER_WIDTH_PX, rect.right + BORDER_WIDTH_PX,
405 | rect.bottom + BORDER_WIDTH_PX, borderPaint);
406 | }
407 |
408 | alphaPatternDrawable.draw(canvas);
409 |
410 | float[] hsv = new float[] { hue, sat, val };
411 | int color = Color.HSVToColor(hsv);
412 | int acolor = Color.HSVToColor(0, hsv);
413 |
414 | alphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, color, acolor, TileMode.CLAMP);
415 |
416 | alphaPaint.setShader(alphaShader);
417 |
418 | canvas.drawRect(rect, alphaPaint);
419 |
420 | if (alphaSliderText != null && !alphaSliderText.equals("")) {
421 | canvas.drawText(alphaSliderText, rect.centerX(), rect.centerY() + DrawingUtils.dpToPx(getContext(), 4),
422 | alphaTextPaint);
423 | }
424 |
425 | Point p = alphaToPoint(alpha);
426 |
427 | RectF r = new RectF();
428 | r.left = p.x - (sliderTrackerSizePx / 2);
429 | r.right = p.x + (sliderTrackerSizePx / 2);
430 | r.top = rect.top - sliderTrackerOffsetPx;
431 | r.bottom = rect.bottom + sliderTrackerOffsetPx;
432 |
433 | canvas.drawRoundRect(r, 2, 2, hueAlphaTrackerPaint);
434 | }
435 |
436 | private Point hueToPoint(float hue) {
437 |
438 | final Rect rect = hueRect;
439 | final float height = rect.height();
440 |
441 | Point p = new Point();
442 |
443 | p.y = (int) (height - (hue * height / 360f) + rect.top);
444 | p.x = rect.left;
445 |
446 | return p;
447 | }
448 |
449 | private Point satValToPoint(float sat, float val) {
450 |
451 | final Rect rect = satValRect;
452 | final float height = rect.height();
453 | final float width = rect.width();
454 |
455 | Point p = new Point();
456 |
457 | p.x = (int) (sat * width + rect.left);
458 | p.y = (int) ((1f - val) * height + rect.top);
459 |
460 | return p;
461 | }
462 |
463 | private Point alphaToPoint(int alpha) {
464 |
465 | final Rect rect = alphaRect;
466 | final float width = rect.width();
467 |
468 | Point p = new Point();
469 |
470 | p.x = (int) (width - (alpha * width / 0xff) + rect.left);
471 | p.y = rect.top;
472 |
473 | return p;
474 | }
475 |
476 | private float[] pointToSatVal(float x, float y) {
477 |
478 | final Rect rect = satValRect;
479 | float[] result = new float[2];
480 |
481 | float width = rect.width();
482 | float height = rect.height();
483 |
484 | if (x < rect.left) {
485 | x = 0f;
486 | } else if (x > rect.right) {
487 | x = width;
488 | } else {
489 | x = x - rect.left;
490 | }
491 |
492 | if (y < rect.top) {
493 | y = 0f;
494 | } else if (y > rect.bottom) {
495 | y = height;
496 | } else {
497 | y = y - rect.top;
498 | }
499 |
500 | result[0] = 1.f / width * x;
501 | result[1] = 1.f - (1.f / height * y);
502 |
503 | return result;
504 | }
505 |
506 | private float pointToHue(float y) {
507 |
508 | final Rect rect = hueRect;
509 |
510 | float height = rect.height();
511 |
512 | if (y < rect.top) {
513 | y = 0f;
514 | } else if (y > rect.bottom) {
515 | y = height;
516 | } else {
517 | y = y - rect.top;
518 | }
519 |
520 | float hue = 360f - (y * 360f / height);
521 |
522 | return hue;
523 | }
524 |
525 | private int pointToAlpha(int x) {
526 |
527 | final Rect rect = alphaRect;
528 | final int width = rect.width();
529 |
530 | if (x < rect.left) {
531 | x = 0;
532 | } else if (x > rect.right) {
533 | x = width;
534 | } else {
535 | x = x - rect.left;
536 | }
537 |
538 | return 0xff - (x * 0xff / width);
539 | }
540 |
541 | @Override public boolean onTouchEvent(MotionEvent event) {
542 | boolean update = false;
543 |
544 | switch (event.getAction()) {
545 |
546 | case MotionEvent.ACTION_DOWN:
547 | startTouchPoint = new Point((int) event.getX(), (int) event.getY());
548 | update = moveTrackersIfNeeded(event);
549 | break;
550 | case MotionEvent.ACTION_MOVE:
551 | update = moveTrackersIfNeeded(event);
552 | break;
553 | case MotionEvent.ACTION_UP:
554 | startTouchPoint = null;
555 | update = moveTrackersIfNeeded(event);
556 | break;
557 | }
558 |
559 | if (update) {
560 | if (onColorChangedListener != null) {
561 | onColorChangedListener.onColorChanged(Color.HSVToColor(alpha, new float[] { hue, sat, val }));
562 | }
563 | invalidate();
564 | return true;
565 | }
566 |
567 | return super.onTouchEvent(event);
568 | }
569 |
570 | private boolean moveTrackersIfNeeded(MotionEvent event) {
571 | if (startTouchPoint == null) {
572 | return false;
573 | }
574 |
575 | boolean update = false;
576 |
577 | int startX = startTouchPoint.x;
578 | int startY = startTouchPoint.y;
579 |
580 | if (hueRect.contains(startX, startY)) {
581 | hue = pointToHue(event.getY());
582 |
583 | update = true;
584 | } else if (satValRect.contains(startX, startY)) {
585 | float[] result = pointToSatVal(event.getX(), event.getY());
586 |
587 | sat = result[0];
588 | val = result[1];
589 |
590 | update = true;
591 | } else if (alphaRect != null && alphaRect.contains(startX, startY)) {
592 | alpha = pointToAlpha((int) event.getX());
593 |
594 | update = true;
595 | }
596 |
597 | return update;
598 | }
599 |
600 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
601 | int finalWidth;
602 | int finalHeight;
603 |
604 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
605 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
606 |
607 | int widthAllowed = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
608 | int heightAllowed = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop();
609 |
610 | if (widthMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.EXACTLY) {
611 | //A exact value has been set in either direction, we need to stay within this size.
612 |
613 | if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
614 | //The with has been specified exactly, we need to adopt the height to fit.
615 | int h = (widthAllowed - panelSpacingPx - huePanelWidthPx);
616 |
617 | if (showAlphaPanel) {
618 | h += panelSpacingPx + alphaPanelHeightPx;
619 | }
620 |
621 | if (h > heightAllowed) {
622 | //We can't fit the view in this container, set the size to whatever was allowed.
623 | finalHeight = heightAllowed;
624 | } else {
625 | finalHeight = h;
626 | }
627 |
628 | finalWidth = widthAllowed;
629 | } else if (heightMode == MeasureSpec.EXACTLY && widthMode != MeasureSpec.EXACTLY) {
630 | //The height has been specified exactly, we need to stay within this height and adopt the width.
631 |
632 | int w = (heightAllowed + panelSpacingPx + huePanelWidthPx);
633 |
634 | if (showAlphaPanel) {
635 | w -= (panelSpacingPx + alphaPanelHeightPx);
636 | }
637 |
638 | if (w > widthAllowed) {
639 | //we can't fit within this container, set the size to whatever was allowed.
640 | finalWidth = widthAllowed;
641 | } else {
642 | finalWidth = w;
643 | }
644 |
645 | finalHeight = heightAllowed;
646 | } else {
647 | //If we get here the dev has set the width and height to exact sizes. For example match_parent or 300dp.
648 | //This will mean that the sat/val panel will not be square but it doesn't matter. It will work anyway.
649 | //In all other senarios our goal is to make that panel square.
650 |
651 | //We set the sizes to exactly what we were told.
652 | finalWidth = widthAllowed;
653 | finalHeight = heightAllowed;
654 | }
655 | } else {
656 | //If no exact size has been set we try to make our view as big as possible
657 | //within the allowed space.
658 |
659 | //Calculate the needed width to layout using max allowed height.
660 | int widthNeeded = (heightAllowed + panelSpacingPx + huePanelWidthPx);
661 |
662 | //Calculate the needed height to layout using max allowed width.
663 | int heightNeeded = (widthAllowed - panelSpacingPx - huePanelWidthPx);
664 |
665 | if (showAlphaPanel) {
666 | widthNeeded -= (panelSpacingPx + alphaPanelHeightPx);
667 | heightNeeded += panelSpacingPx + alphaPanelHeightPx;
668 | }
669 |
670 | boolean widthOk = false;
671 | boolean heightOk = false;
672 |
673 | if (widthNeeded <= widthAllowed) {
674 | widthOk = true;
675 | }
676 |
677 | if (heightNeeded <= heightAllowed) {
678 | heightOk = true;
679 | }
680 |
681 | if (widthOk && heightOk) {
682 | finalWidth = widthAllowed;
683 | finalHeight = heightNeeded;
684 | } else if (!heightOk && widthOk) {
685 | finalHeight = heightAllowed;
686 | finalWidth = widthNeeded;
687 | } else if (!widthOk && heightOk) {
688 | finalHeight = heightNeeded;
689 | finalWidth = widthAllowed;
690 | } else {
691 | finalHeight = heightAllowed;
692 | finalWidth = widthAllowed;
693 | }
694 | }
695 |
696 | setMeasuredDimension(finalWidth + getPaddingLeft() + getPaddingRight(),
697 | finalHeight + getPaddingTop() + getPaddingBottom());
698 | }
699 |
700 | private int getPreferredWidth() {
701 | //Our preferred width and height is 200dp for the square sat / val rectangle.
702 | int width = DrawingUtils.dpToPx(getContext(), 200);
703 |
704 | return (width + huePanelWidthPx + panelSpacingPx);
705 | }
706 |
707 | private int getPreferredHeight() {
708 | int height = DrawingUtils.dpToPx(getContext(), 200);
709 |
710 | if (showAlphaPanel) {
711 | height += panelSpacingPx + alphaPanelHeightPx;
712 | }
713 | return height;
714 | }
715 |
716 | @Override public int getPaddingTop() {
717 | return Math.max(super.getPaddingTop(), mRequiredPadding);
718 | }
719 |
720 | @Override public int getPaddingBottom() {
721 | return Math.max(super.getPaddingBottom(), mRequiredPadding);
722 | }
723 |
724 | @Override public int getPaddingLeft() {
725 | return Math.max(super.getPaddingLeft(), mRequiredPadding);
726 | }
727 |
728 | @Override public int getPaddingRight() {
729 | return Math.max(super.getPaddingRight(), mRequiredPadding);
730 | }
731 |
732 | @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
733 | super.onSizeChanged(w, h, oldw, oldh);
734 |
735 | drawingRect = new Rect();
736 | drawingRect.left = getPaddingLeft();
737 | drawingRect.right = w - getPaddingRight();
738 | drawingRect.top = getPaddingTop();
739 | drawingRect.bottom = h - getPaddingBottom();
740 |
741 | //The need to be recreated because they depend on the size of the view.
742 | valShader = null;
743 | satShader = null;
744 | alphaShader = null;
745 |
746 | // Clear those bitmap caches since the size may have changed.
747 | satValBackgroundCache = null;
748 | hueBackgroundCache = null;
749 |
750 | setUpSatValRect();
751 | setUpHueRect();
752 | setUpAlphaRect();
753 | }
754 |
755 | private void setUpSatValRect() {
756 | //Calculate the size for the big color rectangle.
757 | final Rect dRect = drawingRect;
758 |
759 | int left = dRect.left + BORDER_WIDTH_PX;
760 | int top = dRect.top + BORDER_WIDTH_PX;
761 | int bottom = dRect.bottom - BORDER_WIDTH_PX;
762 | int right = dRect.right - BORDER_WIDTH_PX - panelSpacingPx - huePanelWidthPx;
763 |
764 | if (showAlphaPanel) {
765 | bottom -= (alphaPanelHeightPx + panelSpacingPx);
766 | }
767 |
768 | satValRect = new Rect(left, top, right, bottom);
769 | }
770 |
771 | private void setUpHueRect() {
772 | //Calculate the size for the hue slider on the left.
773 | final Rect dRect = drawingRect;
774 |
775 | int left = dRect.right - huePanelWidthPx + BORDER_WIDTH_PX;
776 | int top = dRect.top + BORDER_WIDTH_PX;
777 | int bottom = dRect.bottom - BORDER_WIDTH_PX - (showAlphaPanel ? (panelSpacingPx + alphaPanelHeightPx) : 0);
778 | int right = dRect.right - BORDER_WIDTH_PX;
779 |
780 | hueRect = new Rect(left, top, right, bottom);
781 | }
782 |
783 | private void setUpAlphaRect() {
784 |
785 | if (!showAlphaPanel) return;
786 |
787 | final Rect dRect = drawingRect;
788 |
789 | int left = dRect.left + BORDER_WIDTH_PX;
790 | int top = dRect.bottom - alphaPanelHeightPx + BORDER_WIDTH_PX;
791 | int bottom = dRect.bottom - BORDER_WIDTH_PX;
792 | int right = dRect.right - BORDER_WIDTH_PX;
793 |
794 | alphaRect = new Rect(left, top, right, bottom);
795 |
796 | alphaPatternDrawable = new AlphaPatternDrawable(DrawingUtils.dpToPx(getContext(), 4));
797 | alphaPatternDrawable.setBounds(Math.round(alphaRect.left), Math.round(alphaRect.top), Math.round(alphaRect.right),
798 | Math.round(alphaRect.bottom));
799 | }
800 |
801 | /**
802 | * Set a OnColorChangedListener to get notified when the color
803 | * selected by the user has changed.
804 | *
805 | * @param listener the listener
806 | */
807 | public void setOnColorChangedListener(OnColorChangedListener listener) {
808 | onColorChangedListener = listener;
809 | }
810 |
811 | /**
812 | * Get the current color this view is showing.
813 | *
814 | * @return the current color.
815 | */
816 | public int getColor() {
817 | return Color.HSVToColor(alpha, new float[] { hue, sat, val });
818 | }
819 |
820 | /**
821 | * Set the color the view should show.
822 | *
823 | * @param color The color that should be selected. #argb
824 | */
825 | public void setColor(int color) {
826 | setColor(color, false);
827 | }
828 |
829 | /**
830 | * Set the color this view should show.
831 | *
832 | * @param color The color that should be selected. #argb
833 | * @param callback If you want to get a callback to your OnColorChangedListener.
834 | */
835 | public void setColor(int color, boolean callback) {
836 |
837 | int alpha = Color.alpha(color);
838 | int red = Color.red(color);
839 | int blue = Color.blue(color);
840 | int green = Color.green(color);
841 |
842 | float[] hsv = new float[3];
843 |
844 | Color.RGBToHSV(red, green, blue, hsv);
845 |
846 | this.alpha = alpha;
847 | hue = hsv[0];
848 | sat = hsv[1];
849 | val = hsv[2];
850 |
851 | if (callback && onColorChangedListener != null) {
852 | onColorChangedListener.onColorChanged(Color.HSVToColor(this.alpha, new float[] { hue, sat, val }));
853 | }
854 |
855 | invalidate();
856 | }
857 |
858 | /**
859 | * Set if the user is allowed to adjust the alpha panel. Default is false.
860 | * If it is set to false no alpha will be set.
861 | *
862 | * @param visible {@code true} to show the alpha slider
863 | */
864 | public void setAlphaSliderVisible(boolean visible) {
865 | if (showAlphaPanel != visible) {
866 | showAlphaPanel = visible;
867 |
868 | /*
869 | * Force recreation.
870 | */
871 | valShader = null;
872 | satShader = null;
873 | alphaShader = null;
874 | hueBackgroundCache = null;
875 | satValBackgroundCache = null;
876 |
877 | requestLayout();
878 | }
879 | }
880 |
881 | /**
882 | * Get color of the tracker slider on the hue and alpha panel.
883 | *
884 | * @return the color value
885 | */
886 | public int getSliderTrackerColor() {
887 | return sliderTrackerColor;
888 | }
889 |
890 | /**
891 | * Set the color of the tracker slider on the hue and alpha panel.
892 | *
893 | * @param color a color value
894 | */
895 | public void setSliderTrackerColor(int color) {
896 | sliderTrackerColor = color;
897 | hueAlphaTrackerPaint.setColor(sliderTrackerColor);
898 | invalidate();
899 | }
900 |
901 | /**
902 | * Get the color of the border surrounding all panels.
903 | */
904 | public int getBorderColor() {
905 | return borderColor;
906 | }
907 |
908 | /**
909 | * Set the color of the border surrounding all panels.
910 | *
911 | * @param color a color value
912 | */
913 | public void setBorderColor(int color) {
914 | borderColor = color;
915 | invalidate();
916 | }
917 |
918 | /**
919 | * Set the text that should be shown in the
920 | * alpha slider. Set to null to disable text.
921 | *
922 | * @param res string resource id.
923 | */
924 | public void setAlphaSliderText(int res) {
925 | String text = getContext().getString(res);
926 | setAlphaSliderText(text);
927 | }
928 |
929 | /**
930 | * Get the current value of the text
931 | * that will be shown in the alpha
932 | * slider.
933 | *
934 | * @return the slider text
935 | */
936 | public String getAlphaSliderText() {
937 | return alphaSliderText;
938 | }
939 |
940 | /**
941 | * Set the text that should be shown in the
942 | * alpha slider. Set to null to disable text.
943 | *
944 | * @param text Text that should be shown.
945 | */
946 | public void setAlphaSliderText(String text) {
947 | alphaSliderText = text;
948 | invalidate();
949 | }
950 |
951 | public interface OnColorChangedListener {
952 |
953 | void onColorChanged(int newColor);
954 | }
955 |
956 | private class BitmapCache {
957 |
958 | public Canvas canvas;
959 | public Bitmap bitmap;
960 | public float value;
961 | }
962 | }
963 |
--------------------------------------------------------------------------------