Skip to content

Instantly share code, notes, and snippets.

@KVinS
Created November 20, 2015 19:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KVinS/f79f8575cd3b5e1b922b to your computer and use it in GitHub Desktop.
Save KVinS/f79f8575cd3b5e1b922b to your computer and use it in GitHub Desktop.
public class ColorPickerView extends View implements View.OnTouchListener {
private OnColorChangeListener mListener;
private int mInitialColor, mInitialAlpha;
private String mKey;
// Константы, определяющие что именно мы устанавливаем в данный момент
protected static final int SET_NONE = -1;
protected static final int SET_COLOR = 0;
protected static final int SET_SATUR = 1;
protected static final int SET_ALPHA = 2;
// и флаг, который будет устанавливаться в одну из этих констант.
// (как-то непонятно я выразился)
private int mMode;
float cx;
float cy;
float rad_1; //
float rad_2; //
float rad_3; //
float r_centr; // радиусы наших окружностей
float r_sel_c; //
float r_sel_s; //
float r_sel_a; //
float r_sel_g; // границы полей выбора
private int size;
private float alpha;
// всякие краски
private Paint p_color = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint p_satur = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint p_alpha = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint p_white = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint p_handl = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint p_center = new Paint(Paint.ANTI_ALIAS_FLAG);
private float deg_col; // углы поворота
private float deg_sat; // указателей - стрелок
private float deg_alp; // ********************
private float lc; //
private float lm; // отступы и выступы линий
private float lw; //
private int mColor;
private int[] argb = new int[]{255, 0, 0, 0};
private float[] hsv = new float[]{0, 1f, 1f};
public ColorPickerView(Context context) {
this(context, null);
}
public ColorPickerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ColorPickerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
setFocusable(true);
p_color.setStyle(Paint.Style.STROKE);
p_satur.setStyle(Paint.Style.STROKE);
p_alpha.setStyle(Paint.Style.STROKE);
p_center.setStyle(Paint.Style.FILL_AND_STROKE);
p_white.setStrokeWidth(2);
p_white.setColor(Color.WHITE);
p_white.setStyle(Paint.Style.STROKE);
p_handl.setStrokeWidth(5);
p_handl.setColor(Color.WHITE);
p_handl.setStrokeCap(Paint.Cap.ROUND);
setOnTouchListener(this);
}
private void calcSizes() {
//
//
cx = size * 0.5f;
cy = cx;
lm = size * 0.043f;
lw = size * 0.035f;
rad_1 = size * 0.44f;
r_sel_g= size * 0.49f;
r_sel_c = size * 0.39f;
rad_2 = size * 0.34f;
r_sel_s = size * 0.29f;
rad_3 = size * 0.24f;
r_sel_a = size * 0.19f;
r_centr = size * 0.18f;
lc = size * 0.08f;
p_color.setStrokeWidth(lc);
p_satur.setStrokeWidth(lc);
p_alpha.setStrokeWidth(lc);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mWidth = measure(widthMeasureSpec);
int mHeight = measure(heightMeasureSpec);
size = Math.min(mWidth, mHeight);
setMeasuredDimension(size, size);
// Вычислили размер доступной области, определили что меньше
// и установили размер нашей View в виде квадрата со стороной в
// высоту или ширину экрана в зависимости от ориентации.
// Вместо Math.min как вариант можно использовать getConfiguration,
// величину size можно умножать на какие-нибудь коэффициенты,
// задавая размер View относительно размера экрана. Например так:
/*int orient = getResources().getConfiguration().orientation;
switch (orient) {
case Configuration.ORIENTATION_PORTRAIT:
size = (int) (measureHeight * port);
break;
case Configuration.ORIENTATION_LANDSCAPE:
size = (int) (measureHeight * land);
break;
}*/
calcSizes();
// И запустили метод для расчетов всяких наших размеров
}
private int measure(int measureSpec) {
int result = 0;
int specMoge = View.MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMoge == MeasureSpec.UNSPECIFIED) result = 200;
else result = specSize;
return result;
}
@Override
protected void onDraw(Canvas c) {
super.onDraw(c);
// Ну а тут будем рисовать
// Для начала проверим, что все работает – нарисуем просто фон
//c.drawColor(Color.BLUE);
//c.drawCircle(cx, cy, rad_1, p_substrate);
c.drawCircle(cx, cy, r_centr, p_center);
drawSaturGradient(c);
drawAlphaGradient(c);
drawColorGradient(c);
drawLines(c);
invalidate();
}
public void setUsedColor(int color) {
float a = ((float)Color.alpha(color)/255);
mColor = color;
Color.colorToHSV(mColor, hsv);
setColScale(hsv[0]);
float deg = 0;
if (hsv[1] == 1) deg = 90 * hsv[2];
else if (hsv[2] == 1) deg = 180 - 90 * hsv[1];
else if (hsv[1] == 0) deg = 360 - 180 * hsv[2];
setSatScale(deg);
setAlphaScale(180 - 180 * a);
if(listener != null) listener.onColorChanged(color);
}
private void drawColorGradient(Canvas c) {
SweepGradient s = null;
int[] sg = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.RED};
s = new SweepGradient(cx, cy, sg, null);
p_color.setShader(s);
c.drawCircle(cx, cy, rad_1, p_color);
}
private void drawSaturGradient(Canvas c) {
SweepGradient s = null;
int[] sg = new int[]{
Color.HSVToColor(new float[]{deg_col, 1, 0}), Color.HSVToColor(new float[]{deg_col, 1, 1}), Color.HSVToColor(new float[]{hsv[0], 0, 1}), Color.HSVToColor(new float[]{hsv[0], 0, 0.5f}), Color.HSVToColor(new float[]{deg_col, 1, 0})
};
s = new SweepGradient(cx, cy, sg, null);
p_satur.setShader(s);
c.drawCircle(cx, cy, rad_2, p_satur);
}
private void drawAlphaGradient(Canvas c) {
// три белых линии на черном фоне как бы помогают визуально
// оценить уровень прозрачности
c.drawCircle(cx, cy, rad_3 - lw, p_white);
c.drawCircle(cx, cy, rad_3, p_white);
c.drawCircle(cx, cy, rad_3 + lw, p_white);
// вытаскиваем компоненты RGB из нашего цвета
int ir = Color.red(mColor);
int ig = Color.green(mColor);
int ib = Color.blue(mColor);
// массив из двух цветов – наш и он же полностью прозрачный
int e = Color.argb(0, ir, ig, ib);
int[] mCol = new int[]{mColor, e, e, mColor};
// Это мы уже проходили
Shader sw = new SweepGradient(cx, cy, mCol, null);
p_alpha.setShader(sw);
c.drawCircle(cx, cy, rad_3, p_alpha);
}
private void drawLines(Canvas c) {
float d = deg_col;
c.rotate(d, cx, cy);
c.drawLine(cx + rad_1 + lm, cy, cx + rad_1 - lm, cy, p_handl);
c.rotate(-d, cx, cy);
d = deg_sat;
c.rotate(d, cx, cy);
c.drawLine(cx + rad_2 + lm, cy, cx + rad_2 - lm, cy, p_handl);
c.rotate(-d, cx, cy);
d = deg_alp;
c.rotate(d, cx, cy);
c.drawLine(cx + rad_3 + lm, cy, cx + rad_3 - lm, cy, p_handl);
c.rotate(-d, cx, cy);
}
protected void setColScale(float f) {
deg_col = f;
hsv[0] = f;
mColor = Color.HSVToColor(argb[0], hsv);
p_center.setColor(mColor);
}
protected void setSatScale(float f) {
deg_sat = f;
if (f < 90) {
hsv[1] = 1;
hsv[2] = f / 90;
} else if (f >= 90 && f < 180) {
hsv[1] = 1 - (f - 90) / 90;
hsv[2] = 1;
} else {
hsv[1] = 0;
hsv[2] = 1 - (f - 180) / 180;
}
mColor = Color.HSVToColor(argb[0], hsv);
p_center.setColor(mColor);
}
protected void setAlphaScale(float f) {
deg_alp = f;
if(deg_alp >= 180){
argb[0] = (int) (255 - (360 - f) / 180 * 255);
}else{
argb[0] = (int) (255 - f / 180 * 255);
}
mColor = Color.HSVToColor(argb[0], hsv);
alpha = (float) Color.alpha(mColor) / 255;
p_center.setColor(mColor);
}
protected float getAngle(float x, float y) {
float deg = 0;
if (x != 0) deg = y / x;
deg = (float) Math.toDegrees(Math.atan(deg));
if (x < 0) deg += 180;
else if (x > 0 && y < 0) deg += 360;
return deg;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
float a = Math.abs(motionEvent.getX() - cx);
float b = Math.abs(motionEvent.getY() - cy);
float c = (float) Math.sqrt(a * a + b * b);
if (c > r_centr) {
if (c > r_sel_c && c <= r_sel_g) mMode = SET_COLOR;
else if (c < r_sel_c && c > r_sel_s) mMode = SET_SATUR;
else if (c < r_sel_s && c > r_sel_a) mMode = SET_ALPHA;
else mMode = SET_NONE;
} else {
mMode = SET_NONE;
}
//else if (c < r_centr) listener.onDismiss(mColor);
break;
case MotionEvent.ACTION_UP:
listener.onDismiss(mColor);
break;
case MotionEvent.ACTION_MOVE:
float x = motionEvent.getX() - cx;
float y = motionEvent.getY() - cy;
switch (mMode) {
case SET_COLOR:
setColScale(getAngle(x, y));
break;
case SET_SATUR:
setSatScale(getAngle(x, y));
break;
case SET_ALPHA:
setAlphaScale(getAngle(x, y));
break;
}
if(listener != null)
listener.onColorChanged(mColor);
invalidate();
break;
}
return true;
}
private OnColorChangeListener listener;
public void setOnColorChangeListener(OnColorChangeListener l) {
this.listener = l;
}
public void reset() {
setUsedColor(Color.WHITE);
if(listener != null) listener.onColorChanged(-1);
}
public interface OnColorChangeListener {
void onDismiss(int color);
void onColorChanged(int color);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment