├── LICENSE ├── README.md ├── build.gradle ├── colorpicker ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── itsaky │ │ └── colorpicker │ │ ├── ColorPickerDialog.java │ │ └── ColorPickerSeekbar.java │ └── res │ ├── drawable │ ├── seekbar_thumb_animation.xml │ ├── seekbar_thumb_animation_backward.xml │ └── seekbar_thumb_vector.xml │ ├── layout │ └── layout_colorpickerview.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle-mvn-push.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Akash Yadav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaterialColorPicker 2 | [![license](https://img.shields.io/github/license/itsaky/MaterialColorPicker.svg?style=flat-square)](https://github.com/itsaky/MaterialColorPicker/blob/master/LICENSE) [![](https://jitpack.io/v/itsaky/MaterialColorPicker.svg)](https://jitpack.io/#itsaky/MaterialColorPicker) 3 | 4 | MaterialColorPicker made for Android. Written in Java with [AIDE](https://play.google.com/store/apps/details?id=com.aide.ui) 5 | 6 | ## Download 7 | 8 | Add it in your root build.gradle at the end of repositories: 9 | ``` 10 | allprojects { 11 | repositories { 12 | ... 13 | maven { url 'https://jitpack.io' } 14 | } 15 | } 16 | ``` 17 | 18 | Add the dependency 19 | ``` 20 | dependencies { 21 | implementation 'com.github.itsaky:MaterialColorPicker:' 22 | } 23 | ``` 24 | 25 | ## Usage 26 | - **1. Create a ColorPickerDialog instance using one of the following methods :** 27 | 28 | - **a.** 29 | ```java 30 | // Alpha slider will be invisible 31 | ColorPickerDialog view = new ColorPickerDialog(this); 32 | ``` 33 | 34 | - **b.** 35 | ```java 36 | // Alpha slider will be visible 37 | ColorPickerDialog view = new ColorPickerDialog(this, "#f44336"); 38 | ``` 39 | 40 | - **c.** 41 | ```java 42 | //Alpha slider will be visible 43 | ColorPickerDialog view = new ColorPickerDialog(this, /*alpha*/255, /*red*/ 255, /*green*/ 255, /*blue*/ 255); 44 | ``` 45 | 46 | - **d.** 47 | ```java 48 | // Alpha slider will be invisible 49 | ColorPickerDialog view = new ColorPickerDialog(this, /*red*/ 255, /*green*/ 255, /*blue*/ 255); 50 | ``` 51 | 52 | - **2. Modify values** 53 | ```java 54 | // Setters 55 | view.setAlpha(255); 56 | view.setRed(255); 57 | view.setGreen(255); 58 | view.setBlue(255); 59 | view.withAlpha(true); // enables alpha slider 60 | view.setCloseOnPicked(false); // Prevents closing of dialog when 'pick' is clicked 61 | ``` 62 | 63 | - **3. Getting values** 64 | ```java 65 | view.getAlpha(); 66 | view.getRed(); 67 | view.getGreen(); 68 | view.getBlue(); 69 | view.getColor(); // returns int value of current color 70 | view.getHexColorCode(); // if withAlpha then with alpha hex value else without it 71 | view.getHexWithAlpha(); 72 | view.getHexWithoutAlpha(); 73 | ``` 74 | 75 | - **4. Callback** 76 | Get callback when 'pick' is clicked 77 | ```java 78 | view.setColorPickerCallback(new ColorPickerDialog.ColorPickerCallback(){ 79 | @Override 80 | public void onColorPicked(int color, String hexColorCode) 81 | { 82 | Toast.makeText(getApplicationContext(), "int[" + color + "] hex[" + hexColorCode + "]", Toast.LENGTH_LONG).show(); 83 | } 84 | }); 85 | ``` 86 | 87 | ## License 88 | - [The MIT License](https://github.com/itsaky/MaterialColorPicker/blob/master/LICENSE) 89 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | 7 | classpath 'com.android.tools.build:gradle:2.3.3' 8 | 9 | 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | maven { 21 | url "https://maven.google.com" 22 | } 23 | maven {url 'https://jitpack.io'} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /colorpicker/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /colorpicker/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.0" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | 14 | buildTypes { 15 | debug { 16 | minifyEnabled false 17 | debuggable false 18 | } 19 | release { 20 | minifyEnabled false 21 | debuggable false 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile 'androidx.appcompat:appcompat:+' 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | } 30 | apply from: '../gradle-mvn-push.gradle' 31 | -------------------------------------------------------------------------------- /colorpicker/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=MaterialColorPicker 2 | POM_ARTIFACT_ID=colorpicker 3 | POM_PACKAGING=aar 4 | -------------------------------------------------------------------------------- /colorpicker/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:/tools/adt-bundle-windows-x86_64-20131030/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 | -------------------------------------------------------------------------------- /colorpicker/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/com/itsaky/colorpicker/ColorPickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.itsaky.colorpicker; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.view.Window; 10 | import android.widget.Button; 11 | import android.widget.EditText; 12 | import android.widget.LinearLayout; 13 | import android.widget.SeekBar; 14 | import android.view.View.OnClickListener; 15 | import android.text.TextWatcher; 16 | import android.text.Editable; 17 | 18 | /** 19 | * Custom Dialog for ColorPicker 20 | * @author Akash 21 | */ 22 | 23 | public class ColorPickerDialog extends Dialog implements SeekBar.OnSeekBarChangeListener, 24 | OnClickListener, 25 | TextWatcher 26 | { 27 | /** 28 | * Fields to store current color values 29 | */ 30 | private int alpha; 31 | private int red; 32 | private int green; 33 | private int blue; 34 | private boolean withAlpha = false; 35 | private boolean closeOnPick = true; 36 | 37 | private ColorPickerSeekbar mAlphaSeek, 38 | mRedSeek, 39 | mGreenSeek, 40 | mBlueSeek; 41 | private LinearLayout mColorView; 42 | private EditText mHexField; 43 | private Button mPickButton; 44 | 45 | /** 46 | * onColorPicked Callback 47 | */ 48 | private ColorPickerCallback mCallback; 49 | 50 | /** 51 | * Initiate with black color with full alpha 52 | * It will not show the Alpha Slider 53 | * @param c Activity 54 | */ 55 | public ColorPickerDialog(Activity c) 56 | { 57 | super(c); 58 | alpha = 255; 59 | withAlpha = false; 60 | red = green = blue = 0; 61 | } 62 | 63 | /** 64 | * Initiate with provided color with alpha 65 | * Shows the alpha slider 66 | * @param c Activity 67 | * @param alpha => alpha value 68 | * @param red => red value 69 | * @param green => green value 70 | * @param blue => blue value 71 | */ 72 | public ColorPickerDialog(Activity c, int alpha, int red, int green, int blue) 73 | { 74 | super(c); 75 | withAlpha = true; 76 | this.alpha = validateColorValue(alpha); 77 | this.red = validateColorValue(red); 78 | this.green = validateColorValue(green); 79 | this.blue = validateColorValue(blue); 80 | } 81 | 82 | /** 83 | * Initiate with provided color with full alpha 84 | * Does not shows the alpha slider 85 | * @param c Activity 86 | * @param red => red value 87 | * @param green => green value 88 | * @param blue => blue value 89 | */ 90 | public ColorPickerDialog(Activity c, int red, int green, int blue) 91 | { 92 | super(c); 93 | withAlpha = false; 94 | this.alpha = 255; 95 | this.red = validateColorValue(red); 96 | this.green = validateColorValue(green); 97 | this.blue = validateColorValue(blue); 98 | } 99 | 100 | /** 101 | * Initiate with color provided 102 | * Shows the alpha slider 103 | * @param c Activity 104 | * @param hexColor Hex Color String 105 | */ 106 | public ColorPickerDialog(Activity c, String hexColor) 107 | { 108 | super(c); 109 | try 110 | { 111 | int col = Color.parseColor(hexColor); 112 | withAlpha = true; 113 | this.alpha = Color.alpha(col); 114 | this.red = Color.red(col); 115 | this.green = Color.green(col); 116 | this.blue = Color.blue(col); 117 | } catch(Exception e) 118 | { 119 | throw new IllegalArgumentException("Invalid hex color string provided to ColorPickerDialog"); 120 | } 121 | } 122 | 123 | /** 124 | * Set the callback for the ColorPicker 125 | * @param listener Listener to attach 126 | */ 127 | public void setColorPickerCallback(ColorPickerCallback callback) 128 | { 129 | this.mCallback = callback; 130 | } 131 | 132 | @Override 133 | protected void onCreate(Bundle savedInstanceState) 134 | { 135 | super.onCreate(savedInstanceState); 136 | 137 | /** 138 | * Disable title for the dialog 139 | * Don't know why it don't work :) 140 | * Maybe you can figure it out.. 141 | */ 142 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 143 | requestWindowFeature(Window.FEATURE_NO_TITLE); 144 | } 145 | 146 | setContentView(R.layout.layout_colorpickerview); 147 | 148 | mAlphaSeek = findViewById(R.id.colorpickerview_alphaSeek); 149 | mRedSeek = findViewById(R.id.colorpickerview_redSeek); 150 | mGreenSeek = findViewById(R.id.colorpickerview_greenSeek); 151 | mBlueSeek = findViewById(R.id.colorpickerview_blueSeek); 152 | mColorView = findViewById(R.id.colorpickerview_colorView); 153 | mHexField = findViewById(R.id.colorpickerview_hexCode); 154 | mPickButton = findViewById(R.id.colorpickerview_pickButton); 155 | 156 | mAlphaSeek.setVisibility(withAlpha ? View.VISIBLE : View.GONE); 157 | 158 | mPickButton.setOnClickListener(this); 159 | 160 | int max = 255; 161 | mAlphaSeek.setMax(max); 162 | mRedSeek.setMax(max); 163 | mGreenSeek.setMax(max); 164 | mBlueSeek.setMax(max); 165 | 166 | mAlphaSeek.addOnSeekbarChangeListener(this); 167 | mRedSeek.addOnSeekbarChangeListener(this); 168 | mGreenSeek.addOnSeekbarChangeListener(this); 169 | mBlueSeek.addOnSeekbarChangeListener(this); 170 | 171 | mAlphaSeek.setThumbColor(Color.parseColor("#9E9E9E")); 172 | mRedSeek.setThumbColor(Color.parseColor("#F44336")); 173 | mGreenSeek.setThumbColor(Color.parseColor("#4CAF50")); 174 | mBlueSeek.setThumbColor(Color.parseColor("#2196F3")); 175 | 176 | mAlphaSeek.setThumbTextColor(Color.parseColor("#EEEEEE")); 177 | mRedSeek.setThumbTextColor(Color.parseColor("#EF9A9A")); 178 | mGreenSeek.setThumbTextColor(Color.parseColor("#A5D6A7")); 179 | mBlueSeek.setThumbTextColor(Color.parseColor("#90CAF9")); 180 | 181 | mAlphaSeek.setProgressColor(Color.parseColor("#BDBDBD")); 182 | mRedSeek.setProgressColor(Color.parseColor("#EF5350")); 183 | mGreenSeek.setProgressColor(Color.parseColor("#66BB6A")); 184 | mBlueSeek.setProgressColor(Color.parseColor("#42A5F5")); 185 | 186 | mHexField.addTextChangedListener(this); 187 | } 188 | 189 | /** 190 | * get current color of the color picker 191 | * @return int value of color 192 | */ 193 | public int getColor() 194 | { 195 | this.alpha = validateColorValue(alpha); 196 | this.red = validateColorValue(red); 197 | this.green = validateColorValue(green); 198 | this.blue = validateColorValue(blue); 199 | return withAlpha ? Color.argb(alpha, red, green, blue) : Color.rgb(red, green, blue); 200 | } 201 | 202 | /** 203 | * Get hex color code of current color 204 | * @return if alphaEnabled then with alpha hex value else without it 205 | */ 206 | public String getHexColorCode() 207 | { 208 | return withAlpha ? getHexWithAlpha() : getHexWithoutAlpha(); 209 | } 210 | 211 | /** 212 | * Get hex color code without alpha hex value 213 | * @return hex string 214 | */ 215 | public String getHexWithoutAlpha() 216 | { 217 | return String.format("#%02X%02X%02X", red, green, blue); 218 | } 219 | 220 | /** 221 | * Get hex color code with alpha hex value 222 | * @return hex string 223 | */ 224 | public String getHexWithAlpha() 225 | { 226 | alpha = validateColorValue(alpha); 227 | return String.format("#%02X%02X%02X%02X", alpha, red, green, blue); 228 | } 229 | 230 | /** 231 | * check if color value is valid or not (between 0 and 255) 232 | * if not valid, set it to 255 233 | * @param color => color value to validate 234 | * @return validated value 235 | */ 236 | private int validateColorValue(int color) 237 | { 238 | return ((color >= 0) && (color <= 255)) ? color : 255; 239 | } 240 | 241 | /** 242 | * toggle alpha slider visibility 243 | * @param withAlpha enable/disable alpha 244 | */ 245 | public void withAlpha(boolean withAlpha) 246 | { 247 | this.withAlpha = withAlpha; 248 | } 249 | 250 | /** 251 | * initiate/re-initiate view 252 | */ 253 | private void initUI() 254 | { 255 | mAlphaSeek.setVisibility( 256 | withAlpha 257 | ? View.VISIBLE 258 | : View.GONE); 259 | 260 | mColorView.setBackgroundColor(getColor()); 261 | 262 | mAlphaSeek.setProgress(alpha); 263 | mRedSeek.setProgress(red); 264 | mGreenSeek.setProgress(green); 265 | mBlueSeek.setProgress(blue); 266 | } 267 | 268 | /** 269 | * enable/disable auto close for dialog 270 | * @param closeOnPicked boolean value 271 | */ 272 | public void setCloseOnPicked(boolean closeOnPicked) 273 | { 274 | this.closeOnPick = closeOnPicked; 275 | } 276 | 277 | @Override 278 | public void onClick(View p1) 279 | { 280 | if(p1.getId() == mPickButton.getId()) 281 | { 282 | if(mCallback != null) 283 | mCallback.onColorPicked(getColor(), getHexColorCode()); 284 | if(closeOnPick) 285 | dismiss(); 286 | } 287 | } 288 | 289 | @Override 290 | public void onProgressChanged(SeekBar p1, int p2, boolean p3) 291 | { 292 | int id = p1.getId(); 293 | if(id == mAlphaSeek.getId()) 294 | { 295 | alpha = p2; 296 | } else if(id == mRedSeek.getId()) 297 | { 298 | red = p2; 299 | } else if(id == mGreenSeek.getId()) 300 | { 301 | green = p2; 302 | } else if(id == mBlueSeek.getId()) 303 | { 304 | blue = p2; 305 | } 306 | 307 | mColorView.setBackgroundColor(getColor()); 308 | /** 309 | * If progress is changed by user, set hex code to EditText 310 | */ 311 | if(p3) 312 | mHexField.setText(getHexColorCode().replace("#", "")); 313 | } 314 | 315 | @Override public void onStartTrackingTouch(SeekBar p1){} 316 | @Override public void onStopTrackingTouch(SeekBar p1){} 317 | 318 | @Override public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4){} 319 | @Override 320 | public void onTextChanged(CharSequence p1, int p2, int p3, int p4) 321 | { 322 | /** 323 | * Try to parse the color entered in EditText 324 | * Text entered in EditText may not always be a Hex Color Code 325 | */ 326 | try 327 | { 328 | int c = Color.parseColor("#" + mHexField.getText().toString()); 329 | alpha = Color.alpha(c); 330 | red = Color.red(c); 331 | green = Color.green(c); 332 | blue = Color.blue(c); 333 | initUI(); 334 | } catch(Exception e){} 335 | } 336 | @Override public void afterTextChanged(Editable p1){} 337 | 338 | @Override 339 | public void show() 340 | { 341 | super.show(); 342 | initUI(); 343 | mHexField.setText(getHexColorCode().replace("#", "")); 344 | } 345 | 346 | public Button getPickButton() 347 | { 348 | return mPickButton; 349 | } 350 | 351 | public ColorPickerSeekbar getAlphaSeekbar() 352 | { 353 | return mAlphaSeek; 354 | } 355 | 356 | public ColorPickerSeekbar getRedSeekbar() 357 | { 358 | return mRedSeek; 359 | } 360 | 361 | public ColorPickerSeekbar getGreenSeekbar() 362 | { 363 | return mGreenSeek; 364 | } 365 | 366 | public ColorPickerSeekbar getBlueSeekbar() 367 | { 368 | return mBlueSeek; 369 | } 370 | 371 | public EditText getHexEditText() 372 | { 373 | return mHexField; 374 | } 375 | 376 | /** 377 | * setters and getters for color values 378 | */ 379 | public void setAlpha(int alpha) 380 | { 381 | this.alpha = alpha; 382 | } 383 | 384 | public int getAlpha() 385 | { 386 | return alpha; 387 | } 388 | 389 | public void setRed(int red) 390 | { 391 | this.red = red; 392 | } 393 | 394 | public int getRed() 395 | { 396 | return red; 397 | } 398 | 399 | public void setGreen(int green) 400 | { 401 | this.green = green; 402 | } 403 | 404 | public int getGreen() 405 | { 406 | return green; 407 | } 408 | 409 | public void setBlue(int blue) 410 | { 411 | this.blue = blue; 412 | } 413 | 414 | public int getBlue() 415 | { 416 | return blue; 417 | } 418 | 419 | /** 420 | * Interface for onColorPicked Callback 421 | */ 422 | public interface ColorPickerCallback 423 | { 424 | public void onColorPicked(int color, String hexColorCode); 425 | } 426 | 427 | } 428 | -------------------------------------------------------------------------------- /colorpicker/src/main/java/com/itsaky/colorpicker/ColorPickerSeekbar.java: -------------------------------------------------------------------------------- 1 | package com.itsaky.colorpicker; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.PorterDuff; 8 | import android.graphics.Rect; 9 | import android.graphics.Typeface; 10 | import android.graphics.drawable.Drawable; 11 | import android.text.TextPaint; 12 | import android.util.AttributeSet; 13 | import android.util.Log; 14 | import android.view.ViewGroup; 15 | import android.widget.SeekBar; 16 | import androidx.vectordrawable.graphics.drawable.Animatable2Compat; 17 | import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; 18 | import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; 19 | import com.itsaky.colorpicker.R; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * Created by IlToro on 06/12/2017 25 | * Modified by Akash for ColorPicker ;) 26 | */ 27 | 28 | public class ColorPickerSeekbar extends SeekBar { 29 | private TextPaint mTextPaint; 30 | private boolean isTextVisible; 31 | private int multiplier = 1; 32 | private String progressText = "0"; 33 | private String formatter = "1"; 34 | private AnimatedVectorDrawableCompat seekBarThumb; 35 | private AnimatedVectorDrawableCompat seekBarThumbBackwards; 36 | private VectorDrawableCompat seekBarThumbNotAnimated; 37 | private final float scale = getContext().getResources().getDisplayMetrics().density; 38 | 39 | private List listeners = new ArrayList<>(); 40 | private int thumbColor = -1; 41 | 42 | public ColorPickerSeekbar(Context context) { 43 | super(context); 44 | method(context); 45 | } 46 | 47 | public ColorPickerSeekbar(Context context, AttributeSet attrs, int defStyle) { 48 | super(context, attrs, defStyle); 49 | method(context); 50 | } 51 | 52 | public ColorPickerSeekbar(final Context context, AttributeSet attrs) { 53 | super(context, attrs); 54 | method(context); 55 | } 56 | 57 | private void method(Context context) throws Resources.NotFoundException 58 | { 59 | isTextVisible = false; 60 | 61 | mTextPaint = new TextPaint(); 62 | mTextPaint.setColor(getResources().getColor(R.color.pink_800)); 63 | mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.seekbar_thumb_text)); 64 | mTextPaint.setTypeface(Typeface.DEFAULT_BOLD); 65 | mTextPaint.setTextAlign(Paint.Align.CENTER); 66 | 67 | final SeekBar thisSeekbar = this; 68 | 69 | if(thumbColor != -1) 70 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 71 | 72 | seekBarThumbNotAnimated = VectorDrawableCompat.create(getResources(), R.drawable.seekbar_thumb_vector, null); 73 | 74 | seekBarThumb = AnimatedVectorDrawableCompat.create(context, R.drawable.seekbar_thumb_animation); 75 | seekBarThumb.registerAnimationCallback(new Animatable2Compat.AnimationCallback() { 76 | @Override 77 | public void onAnimationEnd(Drawable drawable) 78 | { 79 | super.onAnimationEnd(drawable); 80 | if(thumbColor != -1) 81 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 82 | if (thisSeekbar.getThumb() == seekBarThumb) 83 | { 84 | isTextVisible = true; 85 | Log.i("CATs", "AnimationForwards:TRUE"); 86 | } 87 | } 88 | }); 89 | seekBarThumbBackwards = AnimatedVectorDrawableCompat.create(context, R.drawable.seekbar_thumb_animation_backward); 90 | seekBarThumbBackwards.registerAnimationCallback(new Animatable2Compat.AnimationCallback() { 91 | @Override 92 | public void onAnimationStart(Drawable drawable) 93 | { 94 | super.onAnimationStart(drawable); 95 | if(thumbColor != -1) 96 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 97 | isTextVisible = false; 98 | Log.i("CATs", "AnimationBackwards:FALSE"); 99 | } 100 | @Override 101 | public void onAnimationEnd(Drawable drawable) 102 | { 103 | super.onAnimationEnd(drawable); 104 | if(thumbColor != -1) 105 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 106 | thisSeekbar.setThumb(seekBarThumbNotAnimated); 107 | isTextVisible = false; 108 | Log.i("CATs", "AnimationBackwards:FALSE"); 109 | //set height to 20dp 110 | thisSeekbar.getLayoutParams().height = (int)(20 * scale + 0.5f); 111 | //set padding to n 0 n 0 112 | thisSeekbar.setPadding(thisSeekbar.getPaddingLeft(), 0, thisSeekbar.getPaddingRight(), 0); 113 | //set margin top to 0 114 | ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) thisSeekbar.getLayoutParams(); 115 | params.topMargin = 0; 116 | thisSeekbar.requestLayout(); 117 | } 118 | }); 119 | 120 | this.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 121 | @Override 122 | public void onProgressChanged(SeekBar seekBar, int progress, boolean b) 123 | { 124 | progressText = progress + ""; 125 | 126 | //Notify 127 | for(OnSeekBarChangeListener l : listeners) 128 | { 129 | l.onProgressChanged(seekBar, progress, b); 130 | } 131 | 132 | if(thumbColor != -1) 133 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 134 | } 135 | 136 | @Override 137 | public void onStartTrackingTouch(SeekBar seekBar) 138 | { 139 | for(OnSeekBarChangeListener l : listeners) 140 | { 141 | l.onStartTrackingTouch(seekBar); 142 | } 143 | 144 | thisSeekbar.setThumb(seekBarThumb); 145 | seekBarThumb.start(); 146 | //set height to 120dp 147 | thisSeekbar.getLayoutParams().height = (int)(120 * scale + 0.5f); 148 | //set padding to n 100dp n 0 149 | thisSeekbar.setPadding(thisSeekbar.getPaddingLeft(), (int)(100 * scale + 0.5f), thisSeekbar.getPaddingRight(), 0); 150 | ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) thisSeekbar.getLayoutParams(); 151 | params.topMargin = -(int)(100 * scale + 0.5f); 152 | thisSeekbar.requestLayout(); 153 | //set margin top -100dp: do not bother me, i know it's a bad practice, if you have a 154 | //suggetion just open an issue, but i do not promise i will reply :)git 155 | Log.i("CATs", "StartTrackingTouch:"); 156 | 157 | if(thumbColor != -1) 158 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 159 | } 160 | 161 | @Override 162 | public void onStopTrackingTouch(SeekBar seekBar) 163 | { 164 | for(OnSeekBarChangeListener l : listeners) 165 | { 166 | l.onStopTrackingTouch(seekBar); 167 | } 168 | 169 | thisSeekbar.setThumb(seekBarThumbBackwards); 170 | seekBarThumbBackwards.start(); 171 | isTextVisible = false; 172 | Log.i("CATs", "StopTrackingTouch:FALSE"); 173 | 174 | if(thumbColor != -1) 175 | getThumb().setColorFilter(thumbColor, PorterDuff.Mode.SRC_ATOP); 176 | } 177 | }); 178 | } 179 | 180 | /* 181 | Sets the number you want to multiply the progress to: this will NOT affect progress itself 182 | (no use of setProgress() method) but it will just multiply the value getProgress() just before it 183 | is formatted (see onDraw()) 184 | */ 185 | public ColorPickerSeekbar setMultiplier(int m) { 186 | multiplier = m; 187 | return this; 188 | } 189 | /* 190 | Gets the number you want to multiply your progress to; 191 | */ 192 | public int getMultiplier() { 193 | return multiplier; 194 | } 195 | /* 196 | Sets the type of formatter you want, so that you can apply your logic in onDraw() with some 197 | if-else statements 198 | */ 199 | public ColorPickerSeekbar setFormatter(String f) { 200 | formatter = f; 201 | return this; 202 | } 203 | /* 204 | Gets the type of formatter you set 205 | */ 206 | public String getFormatter() { 207 | return formatter; 208 | } 209 | 210 | /* 211 | 212 | Seekbar can only have one listener, 213 | so I added this method to add more than one listener 214 | 215 | Make sure you do not add too much listeners 216 | 217 | @param listener The listener to attach 218 | 219 | */ 220 | public void addOnSeekbarChangeListener(OnSeekBarChangeListener listener) 221 | { 222 | this.listeners.add(listener); 223 | } 224 | 225 | public void setThumbColor(int color) 226 | { 227 | this.thumbColor = color; 228 | } 229 | 230 | public void setThumbTextColor(int color) 231 | { 232 | if(mTextPaint != null) 233 | mTextPaint.setColor(color); 234 | } 235 | 236 | public void setProgressColor(int color) 237 | { 238 | getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_ATOP); 239 | } 240 | 241 | @Override 242 | protected void onDraw(Canvas canvas) { 243 | super.onDraw(canvas); 244 | /* 245 | Write your own logic here, you can change progressText to whatever you want be it $, %, 246 | h-m-s, etc. 247 | 248 | NOTE: there is no TimeValueFormatter here, these five lines below just show you how I used 249 | it 250 | */ 251 | // if (formatter == "1") { 252 | // //no formatting needed 253 | // progressText = Integer.toString(getProgress()*multiplier); 254 | // } else if (formatter == "TimeValueFormatter") { 255 | // //timevalueformatting XXh YYm ZZs (not included here) 256 | // progressText = new TimeValueFormatter().getHHMMSS(getProgress()*multiplier); 257 | // } 258 | 259 | 260 | Rect bounds = new Rect(); 261 | mTextPaint.getTextBounds(progressText, 0, progressText.length(), bounds); 262 | int width = getWidth()-getPaddingLeft()-getPaddingRight(); 263 | float normalizedProgress = (float) getProgress()/getMax(); 264 | 265 | float thumbX = getPaddingLeft()+width*normalizedProgress; 266 | //Mmmh...this assumes the drawable is 200x200dp, the seekbar is 20dp and its padding/negative margin is 100dp 267 | float thumbY = this.getHeight()-(int)(75*scale+0.5f); 268 | /* Don't really know what size you need: here's what I used, 18dp-(1dp*progressText.lenght()) 269 | so that the text will become smaller if text is longer 270 | */ 271 | mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.seekbar_thumb_text)-getResources().getDimensionPixelSize(R.dimen.dp1)*(progressText.length())); 272 | if (isTextVisible) { 273 | canvas.drawText(progressText, thumbX, thumbY, mTextPaint); 274 | } 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/drawable/seekbar_thumb_animation.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/drawable/seekbar_thumb_animation_backward.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 35 | 36 | 44 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/drawable/seekbar_thumb_vector.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /colorpicker/src/main/res/layout/layout_colorpickerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 27 | 28 | 38 | 39 | 49 | 50 | 59 | 60 | 65 | 66 | 74 | 75 | 84 | 85 |