27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/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 {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/color-picker-view/src/main/java/com/github/danielnilsson9/colorpickerview/view/ColorPickerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Daniel Nilsson
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 | *
18 |
19 | * Change Log:
20 | *
21 | * 1.1
22 | * - Fixed buggy measure and layout code. You can now make the view any size you want.
23 | * - Optimization of the drawing using a bitmap cache, a lot faster!
24 | * - Support for hardware acceleration for all but the problematic
25 | * part of the view will still be software rendered but much faster!
26 | * See comment in drawSatValPanel() for more info.
27 | * - Support for declaring some variables in xml.
28 | *
29 | * 1.2 - 2015-05-08
30 | * - More bugs in onMeasure() have been fixed, should handle all cases properly now.
31 | * - View automatically saves its state now.
32 | * - Automatic border color depending on current theme.
33 | * - Code cleanup, trackball support removed since they do not exist anymore.
34 | *
35 | * 1.3 - 2015-05-10
36 | * - Fixed hue bar selection did not align with what was shown in the sat/val panel.
37 | * Fixed by replacing the linear gardient used before. Now drawing individual lines
38 | * of different colors. This was expensive so we now use a bitmap cache for the hue
39 | * panel too.
40 | * - Replaced all RectF used in the layout process with Rect since the
41 | * floating point values was causing layout issues (perfect alignment).
42 | */
43 | package com.github.danielnilsson9.colorpickerview.view;
44 |
45 | import com.github.danielnilsson9.colorpickerview.R;
46 | import com.github.danielnilsson9.colorpickerview.drawable.AlphaPatternDrawable;
47 | import android.annotation.SuppressLint;
48 | import android.content.Context;
49 | import android.content.res.TypedArray;
50 | import android.graphics.Bitmap;
51 | import android.graphics.Bitmap.Config;
52 | import android.graphics.Canvas;
53 | import android.graphics.Color;
54 | import android.graphics.ComposeShader;
55 | import android.graphics.LinearGradient;
56 | import android.graphics.Paint;
57 | import android.graphics.Paint.Align;
58 | import android.graphics.Paint.Style;
59 | import android.graphics.Point;
60 | import android.graphics.PorterDuff;
61 | import android.graphics.Rect;
62 | import android.graphics.RectF;
63 | import android.graphics.Shader;
64 | import android.graphics.Shader.TileMode;
65 | import android.os.Bundle;
66 | import android.os.Parcelable;
67 | import android.util.AttributeSet;
68 | import android.util.Log;
69 | import android.util.TypedValue;
70 | import android.view.MotionEvent;
71 | import android.view.View;
72 |
73 | /**
74 | * Displays a color picker to the user and allow them
75 | * to select a color. A slider for the alpha channel is
76 | * also available. Enable it by setting
77 | * setAlphaSliderVisible(boolean) to true.
78 | * @author Daniel Nilsson
79 | */
80 | public class ColorPickerView extends View{
81 |
82 | public interface OnColorChangedListener{
83 | public void onColorChanged(int newColor);
84 | }
85 |
86 | private final static int DEFAULT_BORDER_COLOR = 0xFF6E6E6E;
87 | private final static int DEFAULT_SLIDER_COLOR = 0xFFBDBDBD;
88 |
89 | private final static int HUE_PANEL_WDITH_DP = 30;
90 | private final static int ALPHA_PANEL_HEIGH_DP = 20;
91 | private final static int PANEL_SPACING_DP = 10;
92 | private final static int CIRCLE_TRACKER_RADIUS_DP = 5;
93 | private final static int SLIDER_TRACKER_SIZE_DP = 4;
94 | private final static int SLIDER_TRACKER_OFFSET_DP = 2;
95 |
96 |
97 | /**
98 | * The width in pixels of the border
99 | * surrounding all color panels.
100 | */
101 | private final static int BORDER_WIDTH_PX = 1;
102 |
103 | /**
104 | * The width in px of the hue panel.
105 | */
106 | private int mHuePanelWidthPx;
107 | /**
108 | * The height in px of the alpha panel
109 | */
110 | private int mAlphaPanelHeightPx;
111 | /**
112 | * The distance in px between the different
113 | * color panels.
114 | */
115 | private int mPanelSpacingPx;
116 | /**
117 | * The radius in px of the color palette tracker circle.
118 | */
119 | private int mCircleTrackerRadiusPx;
120 | /**
121 | * The px which the tracker of the hue or alpha panel
122 | * will extend outside of its bounds.
123 | */
124 | private int mSliderTrackerOffsetPx;
125 | /**
126 | * Height of slider tracker on hue panel,
127 | * width of slider on alpha panel.
128 | */
129 | private int mSliderTrackerSizePx;
130 |
131 |
132 | private Paint mSatValPaint;
133 | private Paint mSatValTrackerPaint;
134 |
135 | private Paint mAlphaPaint;
136 | private Paint mAlphaTextPaint;
137 | private Paint mHueAlphaTrackerPaint;
138 |
139 | private Paint mBorderPaint;
140 |
141 | private Shader mValShader;
142 | private Shader mSatShader;
143 | private Shader mAlphaShader;
144 |
145 |
146 | /*
147 | * We cache a bitmap of the sat/val panel which is expensive to draw each time.
148 | * We can reuse it when the user is sliding the circle picker as long as the hue isn't changed.
149 | */
150 | private BitmapCache mSatValBackgroundCache;
151 | /* We cache the hue background to since its also very expensive now. */
152 | private BitmapCache mHueBackgroundCache;
153 |
154 | /* Current values */
155 | private int mAlpha = 0xff;
156 | private float mHue = 360f;
157 | private float mSat = 0f;
158 | private float mVal = 0f;
159 |
160 | private boolean mShowAlphaPanel = false;
161 | private String mAlphaSliderText = null;
162 | private int mSliderTrackerColor = DEFAULT_SLIDER_COLOR;
163 | private int mBorderColor = DEFAULT_BORDER_COLOR;
164 |
165 |
166 | /**
167 | * Minimum required padding. The offset from the
168 | * edge we must have or else the finger tracker will
169 | * get clipped when it's drawn outside of the view.
170 | */
171 | private int mRequiredPadding;
172 |
173 |
174 | /**
175 | * The Rect in which we are allowed to draw.
176 | * Trackers can extend outside slightly,
177 | * due to the required padding we have set.
178 | */
179 | private Rect mDrawingRect;
180 |
181 | private Rect mSatValRect;
182 | private Rect mHueRect;
183 | private Rect mAlphaRect;
184 |
185 | private Point mStartTouchPoint = null;
186 |
187 | private AlphaPatternDrawable mAlphaPattern;
188 | private OnColorChangedListener mListener;
189 |
190 |
191 | public ColorPickerView(Context context){
192 | this(context, null);
193 | }
194 |
195 | public ColorPickerView(Context context, AttributeSet attrs) {
196 | this(context, attrs, 0);
197 | }
198 |
199 | public ColorPickerView(Context context, AttributeSet attrs, int defStyle) {
200 | super(context, attrs, defStyle);
201 | init(context, attrs);
202 | }
203 |
204 |
205 |
206 | @Override
207 | public Parcelable onSaveInstanceState() {
208 |
209 | Bundle state = new Bundle();
210 | state.putParcelable("instanceState", super.onSaveInstanceState());
211 | state.putInt("alpha", mAlpha);
212 | state.putFloat("hue", mHue);
213 | state.putFloat("sat", mSat);
214 | state.putFloat("val", mVal);
215 | state.putBoolean("show_alpha", mShowAlphaPanel);
216 | state.putString("alpha_text", mAlphaSliderText);
217 |
218 | return state;
219 | }
220 |
221 | @Override
222 | public void onRestoreInstanceState(Parcelable state) {
223 |
224 | if (state instanceof Bundle) {
225 | Bundle bundle = (Bundle) state;
226 |
227 | mAlpha = bundle.getInt("alpha");
228 | mHue = bundle.getFloat("hue");
229 | mSat = bundle.getFloat("sat");
230 | mVal = bundle.getFloat("val");
231 | mShowAlphaPanel = bundle.getBoolean("show_alpha");
232 | mAlphaSliderText = bundle.getString("alpha_text");
233 |
234 |
235 | state = bundle.getParcelable("instanceState");
236 | }
237 | super.onRestoreInstanceState(state);
238 | }
239 |
240 |
241 | private void init(Context context, AttributeSet attrs) {
242 | //Load those if set in xml resource file.
243 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.colorpickerview__ColorPickerView);
244 | mShowAlphaPanel = a.getBoolean(R.styleable.colorpickerview__ColorPickerView_alphaChannelVisible, false);
245 | mAlphaSliderText = a.getString(R.styleable.colorpickerview__ColorPickerView_alphaChannelText);
246 | mSliderTrackerColor = a.getColor(R.styleable.colorpickerview__ColorPickerView_sliderColor, 0xFFBDBDBD);
247 | mBorderColor = a.getColor(R.styleable.colorpickerview__ColorPickerView_borderColor, 0xFF6E6E6E);
248 | a.recycle();
249 |
250 | applyThemeColors(context);
251 |
252 |
253 | mHuePanelWidthPx = DrawingUtils.dpToPx(getContext(), HUE_PANEL_WDITH_DP);
254 | mAlphaPanelHeightPx = DrawingUtils.dpToPx(getContext(), ALPHA_PANEL_HEIGH_DP);
255 | mPanelSpacingPx = DrawingUtils.dpToPx(getContext(), PANEL_SPACING_DP);
256 | mCircleTrackerRadiusPx = DrawingUtils.dpToPx(getContext(), CIRCLE_TRACKER_RADIUS_DP);
257 | mSliderTrackerSizePx = DrawingUtils.dpToPx(getContext(), SLIDER_TRACKER_SIZE_DP);
258 | mSliderTrackerOffsetPx = DrawingUtils.dpToPx(getContext(), SLIDER_TRACKER_OFFSET_DP);
259 |
260 | mRequiredPadding = getResources().getDimensionPixelSize(R.dimen.colorpickerview__required_padding);
261 |
262 | initPaintTools();
263 |
264 | //Needed for receiving trackball motion events.
265 | setFocusable(true);
266 | setFocusableInTouchMode(true);
267 | }
268 |
269 | private void applyThemeColors(Context c) {
270 | // If no specific border/slider color has been
271 | // set we take the default secondary text color
272 | // as border/slider color. Thus it will adopt
273 | // to theme changes automatically.
274 |
275 | final TypedValue value = new TypedValue ();
276 | TypedArray a = c.obtainStyledAttributes(value.data, new int[] { android.R.attr.textColorSecondary });
277 |
278 | if(mBorderColor == DEFAULT_BORDER_COLOR) {
279 | mBorderColor = a.getColor(0, DEFAULT_BORDER_COLOR);
280 | }
281 |
282 | if(mSliderTrackerColor == DEFAULT_SLIDER_COLOR) {
283 | mSliderTrackerColor = a.getColor(0, DEFAULT_SLIDER_COLOR);
284 | }
285 |
286 | a.recycle();
287 | }
288 |
289 | private void initPaintTools(){
290 |
291 | mSatValPaint = new Paint();
292 | mSatValTrackerPaint = new Paint();
293 | mHueAlphaTrackerPaint = new Paint();
294 | mAlphaPaint = new Paint();
295 | mAlphaTextPaint = new Paint();
296 | mBorderPaint = new Paint();
297 |
298 |
299 | mSatValTrackerPaint.setStyle(Style.STROKE);
300 | mSatValTrackerPaint.setStrokeWidth(DrawingUtils.dpToPx(getContext(), 2));
301 | mSatValTrackerPaint.setAntiAlias(true);
302 |
303 | mHueAlphaTrackerPaint.setColor(mSliderTrackerColor);
304 | mHueAlphaTrackerPaint.setStyle(Style.STROKE);
305 | mHueAlphaTrackerPaint.setStrokeWidth(DrawingUtils.dpToPx(getContext(), 2));
306 | mHueAlphaTrackerPaint.setAntiAlias(true);
307 |
308 | mAlphaTextPaint.setColor(0xff1c1c1c);
309 | mAlphaTextPaint.setTextSize(DrawingUtils.dpToPx(getContext(), 14));
310 | mAlphaTextPaint.setAntiAlias(true);
311 | mAlphaTextPaint.setTextAlign(Align.CENTER);
312 | mAlphaTextPaint.setFakeBoldText(true);
313 |
314 | }
315 |
316 |
317 |
318 | @Override
319 | protected void onDraw(Canvas canvas) {
320 | if(mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) {
321 | return;
322 | }
323 |
324 | drawSatValPanel(canvas);
325 | drawHuePanel(canvas);
326 | drawAlphaPanel(canvas);
327 | }
328 |
329 | private void drawSatValPanel(Canvas canvas){
330 | final Rect rect = mSatValRect;
331 |
332 | if(BORDER_WIDTH_PX > 0){
333 | mBorderPaint.setColor(mBorderColor);
334 | canvas.drawRect(mDrawingRect.left, mDrawingRect.top,
335 | rect.right + BORDER_WIDTH_PX,
336 | rect.bottom + BORDER_WIDTH_PX, mBorderPaint);
337 | }
338 |
339 | if(mValShader == null) {
340 | //Black gradient has either not been created or the view has been resized.
341 | mValShader = new LinearGradient(
342 | rect.left, rect.top, rect.left, rect.bottom,
343 | 0xffffffff, 0xff000000, TileMode.CLAMP);
344 | }
345 |
346 |
347 | //If the hue has changed we need to recreate the cache.
348 | if(mSatValBackgroundCache == null || mSatValBackgroundCache.value != mHue) {
349 |
350 | if(mSatValBackgroundCache == null) {
351 | mSatValBackgroundCache = new BitmapCache();
352 | }
353 |
354 | //We create our bitmap in the cache if it doesn't exist.
355 | if(mSatValBackgroundCache.bitmap == null) {
356 | mSatValBackgroundCache.bitmap = Bitmap
357 | .createBitmap(rect.width(), rect.height(), Config.ARGB_8888);
358 | }
359 |
360 | //We create the canvas once so we can draw on our bitmap and the hold on to it.
361 | if(mSatValBackgroundCache.canvas == null) {
362 | mSatValBackgroundCache.canvas = new Canvas(mSatValBackgroundCache.bitmap);
363 | }
364 |
365 | int rgb = Color.HSVToColor(new float[]{mHue,1f,1f});
366 |
367 | mSatShader = new LinearGradient(
368 | rect.left, rect.top, rect.right, rect.top,
369 | 0xffffffff, rgb, TileMode.CLAMP);
370 |
371 | ComposeShader mShader = new ComposeShader(
372 | mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);
373 | mSatValPaint.setShader(mShader);
374 |
375 | // Finally we draw on our canvas, the result will be
376 | // stored in our bitmap which is already in the cache.
377 | // Since this is drawn on a canvas not rendered on
378 | // screen it will automatically not be using the
379 | // hardware acceleration. And this was the code that
380 | // wasn't supported by hardware acceleration which mean
381 | // there is no need to turn it of anymore. The rest of
382 | // the view will still be hw accelerated.
383 | mSatValBackgroundCache.canvas.drawRect(0, 0,
384 | mSatValBackgroundCache.bitmap.getWidth(),
385 | mSatValBackgroundCache.bitmap.getHeight(),
386 | mSatValPaint);
387 |
388 | //We set the hue value in our cache to which hue it was drawn with,
389 | //then we know that if it hasn't changed we can reuse our cached bitmap.
390 | mSatValBackgroundCache.value = mHue;
391 |
392 | }
393 |
394 | // We draw our bitmap from the cached, if the hue has changed
395 | // then it was just recreated otherwise the old one will be used.
396 | canvas.drawBitmap(mSatValBackgroundCache.bitmap, null, rect, null);
397 |
398 | Point p = satValToPoint(mSat, mVal);
399 |
400 | mSatValTrackerPaint.setColor(0xff000000);
401 | canvas.drawCircle(p.x, p.y,
402 | mCircleTrackerRadiusPx - DrawingUtils.dpToPx(getContext(), 1),
403 | mSatValTrackerPaint);
404 |
405 | mSatValTrackerPaint.setColor(0xffdddddd);
406 | canvas.drawCircle(p.x, p.y,
407 | mCircleTrackerRadiusPx, mSatValTrackerPaint);
408 |
409 | }
410 |
411 | private void drawHuePanel(Canvas canvas){
412 | final Rect rect = mHueRect;
413 |
414 | if(BORDER_WIDTH_PX > 0) {
415 | mBorderPaint.setColor(mBorderColor);
416 |
417 | canvas.drawRect(rect.left - BORDER_WIDTH_PX,
418 | rect.top - BORDER_WIDTH_PX,
419 | rect.right + BORDER_WIDTH_PX,
420 | rect.bottom + BORDER_WIDTH_PX,
421 | mBorderPaint);
422 | }
423 |
424 |
425 | if(mHueBackgroundCache == null) {
426 | mHueBackgroundCache = new BitmapCache();
427 | mHueBackgroundCache.bitmap =
428 | Bitmap.createBitmap(rect.width(), rect.height(), Config.ARGB_8888);
429 | mHueBackgroundCache.canvas = new Canvas(mHueBackgroundCache.bitmap);
430 |
431 |
432 | int[] hueColors = new int[(int)(rect.height() + 0.5f)];
433 |
434 | // Generate array of all colors, will be drawn as individual lines.
435 | float h = 360f;
436 | for(int i = 0; i < hueColors.length; i++) {
437 | hueColors[i] = Color.HSVToColor(new float[]{h, 1f,1f});
438 | h -= 360f / hueColors.length;
439 | }
440 |
441 | // Time to draw the hue color gradient,
442 | // its drawn as individual lines which
443 | // will be quite many when the resolution is high
444 | // and/or the panel is large.
445 | Paint linePaint = new Paint();
446 | linePaint.setStrokeWidth(0);
447 | for(int i = 0; i < hueColors.length; i++) {
448 | linePaint.setColor(hueColors[i]);
449 | mHueBackgroundCache.canvas.drawLine(0, i, mHueBackgroundCache.bitmap.getWidth(), i, linePaint);
450 | }
451 | }
452 |
453 |
454 | canvas.drawBitmap(mHueBackgroundCache.bitmap, null, rect, null);
455 |
456 | Point p = hueToPoint(mHue);
457 |
458 | RectF r = new RectF();
459 | r.left = rect.left - mSliderTrackerOffsetPx;
460 | r.right = rect.right + mSliderTrackerOffsetPx;
461 | r.top = p.y - (mSliderTrackerSizePx / 2);
462 | r.bottom = p.y + (mSliderTrackerSizePx / 2);
463 |
464 | canvas.drawRoundRect(r, 2, 2, mHueAlphaTrackerPaint);
465 | }
466 |
467 | private void drawAlphaPanel(Canvas canvas) {
468 | /*
469 | * Will be drawn with hw acceleration, very fast.
470 | * Also the AlphaPatternDrawable is backed by a bitmap
471 | * generated only once if the size does not change.
472 | */
473 |
474 | if(!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return;
475 |
476 | final Rect rect = mAlphaRect;
477 |
478 | if(BORDER_WIDTH_PX > 0){
479 | mBorderPaint.setColor(mBorderColor);
480 | canvas.drawRect(rect.left - BORDER_WIDTH_PX,
481 | rect.top - BORDER_WIDTH_PX,
482 | rect.right + BORDER_WIDTH_PX,
483 | rect.bottom + BORDER_WIDTH_PX,
484 | mBorderPaint);
485 | }
486 |
487 | mAlphaPattern.draw(canvas);
488 |
489 | float[] hsv = new float[]{mHue,mSat,mVal};
490 | int color = Color.HSVToColor(hsv);
491 | int acolor = Color.HSVToColor(0, hsv);
492 |
493 | mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
494 | color, acolor, TileMode.CLAMP);
495 |
496 |
497 | mAlphaPaint.setShader(mAlphaShader);
498 |
499 | canvas.drawRect(rect, mAlphaPaint);
500 |
501 | if(mAlphaSliderText != null && !mAlphaSliderText.equals("")){
502 | canvas.drawText(mAlphaSliderText, rect.centerX(),
503 | rect.centerY() + DrawingUtils.dpToPx(getContext(), 4),
504 | mAlphaTextPaint);
505 | }
506 |
507 |
508 | Point p = alphaToPoint(mAlpha);
509 |
510 | RectF r = new RectF();
511 | r.left = p.x - (mSliderTrackerSizePx / 2);
512 | r.right = p.x + (mSliderTrackerSizePx / 2);
513 | r.top = rect.top - mSliderTrackerOffsetPx;
514 | r.bottom = rect.bottom + mSliderTrackerOffsetPx;
515 |
516 | canvas.drawRoundRect(r, 2, 2, mHueAlphaTrackerPaint);
517 | }
518 |
519 |
520 | private Point hueToPoint(float hue){
521 |
522 | final Rect rect = mHueRect;
523 | final float height = rect.height();
524 |
525 | Point p = new Point();
526 |
527 | p.y = (int) (height - (hue * height / 360f) + rect.top);
528 | p.x = (int) rect.left;
529 |
530 | return p;
531 | }
532 |
533 | private Point satValToPoint(float sat, float val){
534 |
535 | final Rect rect = mSatValRect;
536 | final float height = rect.height();
537 | final float width = rect.width();
538 |
539 | Point p = new Point();
540 |
541 | p.x = (int) (sat * width + rect.left);
542 | p.y = (int) ((1f - val) * height + rect.top);
543 |
544 | return p;
545 | }
546 |
547 | private Point alphaToPoint(int alpha){
548 |
549 | final Rect rect = mAlphaRect;
550 | final float width = rect.width();
551 |
552 | Point p = new Point();
553 |
554 | p.x = (int) (width - (alpha * width / 0xff) + rect.left);
555 | p.y = (int) rect.top;
556 |
557 | return p;
558 |
559 | }
560 |
561 | private float[] pointToSatVal(float x, float y){
562 |
563 | final Rect rect = mSatValRect;
564 | float[] result = new float[2];
565 |
566 | float width = rect.width();
567 | float height = rect.height();
568 |
569 | if (x < rect.left){
570 | x = 0f;
571 | }
572 | else if(x > rect.right){
573 | x = width;
574 | }
575 | else{
576 | x = x - rect.left;
577 | }
578 |
579 | if (y < rect.top){
580 | y = 0f;
581 | }
582 | else if(y > rect.bottom){
583 | y = height;
584 | }
585 | else{
586 | y = y - rect.top;
587 | }
588 |
589 |
590 | result[0] = 1.f / width * x;
591 | result[1] = 1.f - (1.f / height * y);
592 |
593 | return result;
594 | }
595 |
596 | private float pointToHue(float y){
597 |
598 | final Rect rect = mHueRect;
599 |
600 | float height = rect.height();
601 |
602 | if (y < rect.top){
603 | y = 0f;
604 | }
605 | else if(y > rect.bottom){
606 | y = height;
607 | }
608 | else{
609 | y = y - rect.top;
610 | }
611 |
612 |
613 | float hue = 360f - (y * 360f / height);
614 | Log.d("color-picker-view", "Hue: " + hue);
615 |
616 | return hue;
617 | }
618 |
619 | private int pointToAlpha(int x){
620 |
621 | final Rect rect = mAlphaRect;
622 | final int width = (int) rect.width();
623 |
624 | if(x < rect.left){
625 | x = 0;
626 | }
627 | else if(x > rect.right){
628 | x = width;
629 | }
630 | else{
631 | x = x - (int)rect.left;
632 | }
633 |
634 | return 0xff - (x * 0xff / width);
635 |
636 | }
637 |
638 |
639 | @SuppressLint("ClickableViewAccessibility")
640 | @Override
641 | public boolean onTouchEvent(MotionEvent event) {
642 | boolean update = false;
643 |
644 | switch(event.getAction()){
645 |
646 | case MotionEvent.ACTION_DOWN:
647 | mStartTouchPoint = new Point((int)event.getX(), (int)event.getY());
648 | update = moveTrackersIfNeeded(event);
649 | break;
650 | case MotionEvent.ACTION_MOVE:
651 | update = moveTrackersIfNeeded(event);
652 | break;
653 | case MotionEvent.ACTION_UP:
654 | mStartTouchPoint = null;
655 | update = moveTrackersIfNeeded(event);
656 | break;
657 | }
658 |
659 | if(update){
660 | if(mListener != null){
661 | mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));
662 | }
663 | invalidate();
664 | return true;
665 | }
666 |
667 | return super.onTouchEvent(event);
668 | }
669 |
670 | private boolean moveTrackersIfNeeded(MotionEvent event){
671 | if(mStartTouchPoint == null) {
672 | return false;
673 | }
674 |
675 | boolean update = false;
676 |
677 | int startX = mStartTouchPoint.x;
678 | int startY = mStartTouchPoint.y;
679 |
680 | if(mHueRect.contains(startX, startY)){
681 | mHue = pointToHue(event.getY());
682 |
683 | update = true;
684 | }
685 | else if(mSatValRect.contains(startX, startY)){
686 | float[] result = pointToSatVal(event.getX(), event.getY());
687 |
688 | mSat = result[0];
689 | mVal = result[1];
690 |
691 | update = true;
692 | }
693 | else if(mAlphaRect != null && mAlphaRect.contains(startX, startY)){
694 | mAlpha = pointToAlpha((int)event.getX());
695 |
696 | update = true;
697 | }
698 |
699 | return update;
700 | }
701 |
702 |
703 | @Override
704 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
705 | int finalWidth = 0;
706 | int finalHeight = 0;
707 |
708 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
709 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
710 |
711 | int widthAllowed = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
712 | int heightAllowed = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop();
713 |
714 |
715 | //Log.d("color-picker-view", "widthMode: " + modeToString(widthMode) + " heightMode: " + modeToString(heightMode) + " widthAllowed: " + widthAllowed + " heightAllowed: " + heightAllowed);
716 |
717 | if(widthMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.EXACTLY) {
718 | //A exact value has been set in either direction, we need to stay within this size.
719 |
720 | if(widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
721 | //The with has been specified exactly, we need to adopt the height to fit.
722 | int h = (int) (widthAllowed - mPanelSpacingPx - mHuePanelWidthPx);
723 |
724 | if(mShowAlphaPanel) {
725 | h += mPanelSpacingPx + mAlphaPanelHeightPx;
726 | }
727 |
728 | if(h > heightAllowed) {
729 | //We can't fit the view in this container, set the size to whatever was allowed.
730 | finalHeight = heightAllowed;
731 | }
732 | else {
733 | finalHeight = h;
734 | }
735 |
736 | finalWidth = widthAllowed;
737 |
738 | }
739 | else if(heightMode == MeasureSpec.EXACTLY && widthMode != MeasureSpec.EXACTLY) {
740 | //The height has been specified exactly, we need to stay within this height and adopt the width.
741 |
742 | int w = (int) (heightAllowed + mPanelSpacingPx + mHuePanelWidthPx);
743 |
744 | if(mShowAlphaPanel) {
745 | w -= (mPanelSpacingPx + mAlphaPanelHeightPx);
746 | }
747 |
748 | if(w > widthAllowed) {
749 | //we can't fit within this container, set the size to whatever was allowed.
750 | finalWidth = widthAllowed;
751 | }
752 | else {
753 | finalWidth = w;
754 | }
755 |
756 | finalHeight = heightAllowed;
757 |
758 | }
759 | else {
760 | //If we get here the dev has set the width and height to exact sizes. For example match_parent or 300dp.
761 | //This will mean that the sat/val panel will not be square but it doesn't matter. It will work anyway.
762 | //In all other senarios our goal is to make that panel square.
763 |
764 | //We set the sizes to exactly what we were told.
765 | finalWidth = widthAllowed;
766 | finalHeight = heightAllowed;
767 | }
768 |
769 | }
770 | else {
771 | //If no exact size has been set we try to make our view as big as possible
772 | //within the allowed space.
773 |
774 | //Calculate the needed width to layout using max allowed height.
775 | int widthNeeded = (int) (heightAllowed + mPanelSpacingPx + mHuePanelWidthPx);
776 |
777 | //Calculate the needed height to layout using max allowed width.
778 | int heightNeeded = (int) (widthAllowed - mPanelSpacingPx - mHuePanelWidthPx);
779 |
780 | if(mShowAlphaPanel) {
781 | widthNeeded -= (mPanelSpacingPx + mAlphaPanelHeightPx);
782 | heightNeeded += mPanelSpacingPx + mAlphaPanelHeightPx;
783 | }
784 |
785 | boolean widthOk = false;
786 | boolean heightOk = false;
787 |
788 | if(widthNeeded <= widthAllowed) {
789 | widthOk = true;
790 | }
791 |
792 | if(heightNeeded <= heightAllowed) {
793 | heightOk = true;
794 | }
795 |
796 |
797 | //Log.d("color-picker-view", "Size - Allowed w: " + widthAllowed + " h: " + heightAllowed + " Needed w:" + widthNeeded + " h: " + heightNeeded);
798 |
799 |
800 | if(widthOk && heightOk) {
801 | finalWidth = widthAllowed;
802 | finalHeight = heightNeeded;
803 | }
804 | else if(!heightOk && widthOk) {
805 | finalHeight = heightAllowed;
806 | finalWidth = widthNeeded;
807 | }
808 | else if(!widthOk && heightOk) {
809 | finalHeight = heightNeeded;
810 | finalWidth = widthAllowed;
811 | }
812 | else {
813 | finalHeight = heightAllowed;
814 | finalWidth = widthAllowed;
815 | }
816 |
817 | }
818 |
819 | //Log.d("color-picker-view", "Final Size: " + finalWidth + "x" + finalHeight);
820 |
821 | setMeasuredDimension(finalWidth + getPaddingLeft() + getPaddingRight(),
822 | finalHeight + getPaddingTop() + getPaddingBottom());
823 | }
824 |
825 | private int getPreferredWidth(){
826 | //Our preferred width and height is 200dp for the square sat / val rectangle.
827 | int width = DrawingUtils.dpToPx(getContext(), 200);
828 |
829 | return (int) (width + mHuePanelWidthPx + mPanelSpacingPx);
830 | }
831 |
832 | private int getPreferredHeight(){
833 | int height = DrawingUtils.dpToPx(getContext(), 200);
834 |
835 | if(mShowAlphaPanel){
836 | height += mPanelSpacingPx + mAlphaPanelHeightPx;
837 | }
838 | return height;
839 | }
840 |
841 | @Override
842 | public int getPaddingTop() {
843 | return Math.max(super.getPaddingTop(), mRequiredPadding);
844 | }
845 |
846 | @Override
847 | public int getPaddingBottom() {
848 | return Math.max(super.getPaddingBottom(), mRequiredPadding);
849 | }
850 |
851 | @Override
852 | public int getPaddingLeft() {
853 | return Math.max(super.getPaddingLeft(), mRequiredPadding);
854 | }
855 |
856 | @Override
857 | public int getPaddingRight() {
858 | return Math.max(super.getPaddingRight(), mRequiredPadding);
859 | }
860 |
861 |
862 |
863 | @Override
864 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
865 | super.onSizeChanged(w, h, oldw, oldh);
866 |
867 | mDrawingRect = new Rect();
868 | mDrawingRect.left = getPaddingLeft();
869 | mDrawingRect.right = w - getPaddingRight();
870 | mDrawingRect.top = getPaddingTop();
871 | mDrawingRect.bottom = h - getPaddingBottom();
872 |
873 | //The need to be recreated because they depend on the size of the view.
874 | mValShader = null;
875 | mSatShader = null;
876 | mAlphaShader = null;;
877 |
878 | // Clear those bitmap caches since the size may have changed.
879 | mSatValBackgroundCache = null;
880 | mHueBackgroundCache = null;
881 |
882 | //Log.d("color-picker-view", "Size: " + w + "x" + h);
883 |
884 | setUpSatValRect();
885 | setUpHueRect();
886 | setUpAlphaRect();
887 | }
888 |
889 | private void setUpSatValRect(){
890 | //Calculate the size for the big color rectangle.
891 | final Rect dRect = mDrawingRect;
892 |
893 | int left = dRect.left + BORDER_WIDTH_PX;
894 | int top = dRect.top + BORDER_WIDTH_PX;
895 | int bottom = dRect.bottom - BORDER_WIDTH_PX;
896 | int right = dRect.right - BORDER_WIDTH_PX - mPanelSpacingPx - mHuePanelWidthPx;
897 |
898 |
899 | if(mShowAlphaPanel) {
900 | bottom -= (mAlphaPanelHeightPx + mPanelSpacingPx);
901 | }
902 |
903 | mSatValRect = new Rect(left,top, right, bottom);
904 | }
905 |
906 | private void setUpHueRect(){
907 | //Calculate the size for the hue slider on the left.
908 | final Rect dRect = mDrawingRect;
909 |
910 | int left = dRect.right - mHuePanelWidthPx + BORDER_WIDTH_PX;
911 | int top = dRect.top + BORDER_WIDTH_PX;
912 | int bottom = dRect.bottom - BORDER_WIDTH_PX - (mShowAlphaPanel ? (mPanelSpacingPx + mAlphaPanelHeightPx) : 0);
913 | int right = dRect.right - BORDER_WIDTH_PX;
914 |
915 | mHueRect = new Rect(left, top, right, bottom);
916 | }
917 |
918 | private void setUpAlphaRect(){
919 |
920 | if(!mShowAlphaPanel) return;
921 |
922 | final Rect dRect = mDrawingRect;
923 |
924 | int left = dRect.left + BORDER_WIDTH_PX;
925 | int top = dRect.bottom - mAlphaPanelHeightPx + BORDER_WIDTH_PX;
926 | int bottom = dRect.bottom - BORDER_WIDTH_PX;
927 | int right = dRect.right - BORDER_WIDTH_PX;
928 |
929 | mAlphaRect = new Rect(left, top, right, bottom);
930 |
931 |
932 | mAlphaPattern = new AlphaPatternDrawable(DrawingUtils.dpToPx(getContext(), 5));
933 | mAlphaPattern.setBounds(Math.round(mAlphaRect.left), Math
934 | .round(mAlphaRect.top), Math.round(mAlphaRect.right), Math
935 | .round(mAlphaRect.bottom));
936 | }
937 |
938 |
939 | /**
940 | * Set a OnColorChangedListener to get notified when the color
941 | * selected by the user has changed.
942 | * @param listener
943 | */
944 | public void setOnColorChangedListener(OnColorChangedListener listener){
945 | mListener = listener;
946 | }
947 |
948 | /**
949 | * Get the current color this view is showing.
950 | * @return the current color.
951 | */
952 | public int getColor(){
953 | return Color.HSVToColor(mAlpha, new float[]{mHue,mSat,mVal});
954 | }
955 |
956 | /**
957 | * Set the color the view should show.
958 | * @param color The color that should be selected. #argb
959 | */
960 | public void setColor(int color){
961 | setColor(color, false);
962 | }
963 |
964 | /**
965 | * Set the color this view should show.
966 | * @param color The color that should be selected. #argb
967 | * @param callback If you want to get a callback to
968 | * your OnColorChangedListener.
969 | */
970 | public void setColor(int color, boolean callback){
971 |
972 | int alpha = Color.alpha(color);
973 | int red = Color.red(color);
974 | int blue = Color.blue(color);
975 | int green = Color.green(color);
976 |
977 | float[] hsv = new float[3];
978 |
979 | Color.RGBToHSV(red, green, blue, hsv);
980 |
981 | mAlpha = alpha;
982 | mHue = hsv[0];
983 | mSat = hsv[1];
984 | mVal = hsv[2];
985 |
986 | if(callback && mListener != null){
987 | mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));
988 | }
989 |
990 | invalidate();
991 | }
992 |
993 | /**
994 | * Set if the user is allowed to adjust the alpha panel. Default is false.
995 | * If it is set to false no alpha will be set.
996 | * @param visible
997 | */
998 | public void setAlphaSliderVisible(boolean visible){
999 | if(mShowAlphaPanel != visible){
1000 | mShowAlphaPanel = visible;
1001 |
1002 | /*
1003 | * Force recreation.
1004 | */
1005 | mValShader = null;
1006 | mSatShader = null;
1007 | mAlphaShader = null;
1008 | mHueBackgroundCache = null;
1009 | mSatValBackgroundCache = null;
1010 |
1011 | requestLayout();
1012 | }
1013 |
1014 | }
1015 |
1016 | /**
1017 | * Set the color of the tracker slider on the hue and alpha panel.
1018 | * @param color
1019 | */
1020 | public void setSliderTrackerColor(int color){
1021 | mSliderTrackerColor = color;
1022 | mHueAlphaTrackerPaint.setColor(mSliderTrackerColor);
1023 | invalidate();
1024 | }
1025 |
1026 | /**
1027 | * Get color of the tracker slider on the hue and alpha panel.
1028 | * @return
1029 | */
1030 | public int getSliderTrackerColor(){
1031 | return mSliderTrackerColor;
1032 | }
1033 |
1034 | /**
1035 | * Set the color of the border surrounding all panels.
1036 | * @param color
1037 | */
1038 | public void setBorderColor(int color){
1039 | mBorderColor = color;
1040 | invalidate();
1041 | }
1042 |
1043 | /**
1044 | * Get the color of the border surrounding all panels.
1045 | */
1046 | public int getBorderColor(){
1047 | return mBorderColor;
1048 | }
1049 |
1050 | /**
1051 | * Set the text that should be shown in the
1052 | * alpha slider. Set to null to disable text.
1053 | * @param res string resource id.
1054 | */
1055 | public void setAlphaSliderText(int res){
1056 | String text = getContext().getString(res);
1057 | setAlphaSliderText(text);
1058 | }
1059 |
1060 | /**
1061 | * Set the text that should be shown in the
1062 | * alpha slider. Set to null to disable text.
1063 | * @param text Text that should be shown.
1064 | */
1065 | public void setAlphaSliderText(String text){
1066 | mAlphaSliderText = text;
1067 | invalidate();
1068 | }
1069 |
1070 | /**
1071 | * Get the current value of the text
1072 | * that will be shown in the alpha
1073 | * slider.
1074 | * @return
1075 | */
1076 | public String getAlphaSliderText(){
1077 | return mAlphaSliderText;
1078 | }
1079 |
1080 |
1081 | private class BitmapCache {
1082 | public Canvas canvas;
1083 | public Bitmap bitmap;
1084 | public float value;
1085 | }
1086 |
1087 | }
1088 |
--------------------------------------------------------------------------------