package com.hdl.sdk.ttl_sdk.utlis;
|
|
import android.animation.ValueAnimator;
|
import android.content.Context;
|
import android.content.res.Resources;
|
import android.content.res.TypedArray;
|
import android.graphics.BlurMaskFilter;
|
import android.graphics.Canvas;
|
import android.graphics.Color;
|
import android.graphics.MaskFilter;
|
import android.graphics.Paint;
|
import android.graphics.Path;
|
import android.graphics.Point;
|
import android.graphics.RadialGradient;
|
import android.graphics.RectF;
|
import android.graphics.Region;
|
import android.graphics.Shader;
|
import android.graphics.SweepGradient;
|
import android.support.annotation.ColorInt;
|
import android.support.annotation.Nullable;
|
import android.util.AttributeSet;
|
import android.util.DisplayMetrics;
|
import android.view.MotionEvent;
|
import android.view.View;
|
|
import com.hdl.sdk.ttl_sdk.R;
|
|
import java.util.Locale;
|
|
/**
|
* Created by Tong on 2021/10/27.
|
* Rgb颜色圆环选择器
|
*/
|
public class RGBColorPicker extends View {
|
|
private int mWidth, mHeight;
|
|
//色
|
private SweepGradient mHueShader;
|
//饱和度
|
private RadialGradient mSaturationShader;
|
|
//色板画笔
|
private Paint mPalettePaint;
|
|
//圆盘范围
|
private final Region mPaletteScopeRegion = new Region();
|
|
private Paint paint;
|
|
|
//指针半径
|
private int markSize;
|
private int markColor;
|
|
private int mCurrentColor;
|
|
private MaskFilter maskFilter;
|
|
private float touchX = Float.MAX_VALUE;
|
private float touchY = Float.MAX_VALUE;
|
|
private ColorListener listener;
|
|
private ValueAnimator mDelayAnim;
|
|
public abstract static class DelayColorListener implements ColorListener {
|
|
/**
|
* 延迟500毫秒
|
*/
|
private static final long DEF_DELAY = 500;
|
|
private long lastTime = 0;
|
|
private long delay = DEF_DELAY;
|
|
public DelayColorListener(long delay) {
|
this.delay = delay;
|
}
|
|
public DelayColorListener() {
|
}
|
|
public abstract void onDelayColorChanged(@ColorInt int color, boolean fromUser);
|
|
|
@Override
|
public void onColorSelected(int color, boolean fromUser) {
|
onDelayColorChanged(color, fromUser);
|
}
|
|
@Override
|
public void onColorChange(int color, boolean fromUser) {
|
if (System.currentTimeMillis() - lastTime > delay) {
|
onDelayColorChanged(color, fromUser);
|
lastTime = System.currentTimeMillis();
|
}
|
}
|
}
|
|
public interface ColorListener {
|
/**
|
* 稳定
|
*/
|
void onColorSelected(@ColorInt int color, boolean fromUser);
|
|
/**
|
* 颜色变化
|
*/
|
void onColorChange(@ColorInt int color, boolean fromUser);
|
}
|
|
public RGBColorPicker(Context context) {
|
this(context, null);
|
}
|
|
public RGBColorPicker(Context context, @Nullable AttributeSet attrs) {
|
this(context, attrs, 0);
|
}
|
|
public RGBColorPicker(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
super(context, attrs, defStyleAttr);
|
if (attrs != null) {
|
TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.RGBColorPicker, defStyleAttr, 0);
|
markColor = a.getColor(R.styleable.RGBColorPicker_markColor, Color.WHITE);
|
|
markSize = a.getDimensionPixelOffset(R.styleable.RGBColorPicker_markSize, 0);
|
|
mCurrentColor = a.getColor(R.styleable.RGBColorPicker_markColor, Color.WHITE);
|
|
a.recycle();
|
}
|
init();
|
}
|
|
private void init() {
|
|
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
paint.setStyle(Paint.Style.FILL);
|
paint.setStrokeCap(Paint.Cap.ROUND);
|
|
|
mPalettePaint = new Paint();
|
|
}
|
|
@Override
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
super.onSizeChanged(w, h, oldw, oldh);
|
this.mWidth = getWidth();
|
this.mHeight = getHeight();
|
initPalette();
|
|
}
|
|
|
public void setColorListener(ColorListener listener) {
|
this.listener = listener;
|
}
|
|
@Override
|
protected void onDraw(Canvas canvas) {
|
drawPalette(canvas);
|
drawDropper(canvas);
|
}
|
|
/**
|
* 初始化调色板
|
*/
|
private void initPalette() {
|
float centerX = mWidth * 0.5f;
|
float centerY = mHeight * 0.5f;
|
float radius = Math.min(centerX, centerY);
|
|
mHueShader =
|
new SweepGradient(
|
mWidth * 0.5f,
|
mHeight * 0.5f,
|
new int[]{
|
Color.RED,
|
Color.MAGENTA,
|
Color.BLUE,
|
Color.CYAN,
|
Color.GREEN,
|
Color.YELLOW,
|
Color.RED,
|
|
},
|
new float[]{0.000f, 0.166f, 0.333f, 0.499f, 0.666f, 0.833f, 0.999f});
|
|
|
mSaturationShader =
|
new RadialGradient(
|
centerX, centerY, radius, Color.WHITE, Color.parseColor("#00FFFFFF"), Shader.TileMode.CLAMP);
|
|
|
//色盘范围
|
final Path mPaletteScopePath = new Path();
|
mPaletteScopePath.addCircle(centerX, centerY, radius - markSize * 0.5f, Path.Direction.CW);
|
|
final RectF bounds = new RectF();
|
mPaletteScopePath.computeBounds(bounds, true);
|
|
mPaletteScopeRegion.setPath(mPaletteScopePath, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));
|
|
maskFilter = new BlurMaskFilter(markSize * 0.1f, BlurMaskFilter.Blur.OUTER);
|
|
}
|
|
/**
|
* 画取色器
|
*/
|
private void drawDropper(Canvas canvas) {
|
if (maskFilter == null) return;
|
final float centerX = mWidth * 0.5f;
|
final float centerY = mHeight * 0.5f;
|
final float radius = Math.min(centerX, centerY);
|
final Point point = getNearPoint(touchX, touchY, centerX, centerY, radius, markSize / 2);
|
|
float x = point.x;
|
float y = point.y;
|
|
paint.reset();
|
paint.setStyle(Paint.Style.STROKE);
|
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
paint.setMaskFilter(maskFilter);
|
paint.setColor(Color.BLACK);
|
canvas.drawCircle(x, y, markSize * 0.5f, paint);
|
|
paint.reset();
|
paint.setStyle(Paint.Style.FILL);
|
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
paint.setColor(markColor);
|
paint.setStrokeWidth(dp2pxAdapt(0.5f));
|
paint.setColor(Color.WHITE);
|
paint.setStyle(Paint.Style.STROKE);
|
canvas.drawCircle(x, y, markSize * 0.5f, paint);
|
}
|
|
/**
|
* 画调色板
|
*/
|
private void drawPalette(Canvas canvas) {
|
final float centerX = mWidth * 0.5f;
|
final float centerY = mHeight * 0.5f;
|
final float radius = Math.min(centerX, centerY);
|
|
mPalettePaint.reset();
|
mPalettePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
mPalettePaint.setShader(mHueShader);
|
canvas.drawCircle(centerX, centerY, radius, mPalettePaint);
|
|
|
mPalettePaint.reset();
|
mPalettePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
mPalettePaint.setShader(mSaturationShader);
|
canvas.drawCircle(centerX, centerY, radius, mPalettePaint);
|
|
|
}
|
|
@Override
|
public boolean onTouchEvent(MotionEvent event) {
|
if (mDelayAnim != null) {
|
mDelayAnim.cancel();
|
}
|
float x = event.getX();
|
float y = event.getY();
|
|
int color = getColorByPoint(x, y);
|
this.mCurrentColor = color;
|
switch (event.getAction()) {
|
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_MOVE:
|
|
if (listener != null) {
|
listener.onColorChange(color, true);
|
}
|
touchX = x;
|
touchY = y;
|
invalidate();
|
|
|
return true;
|
case MotionEvent.ACTION_UP:
|
|
if (listener != null) {
|
listener.onColorChange(color, true);
|
listener.onColorSelected(color, true);
|
}
|
touchX = x;
|
touchY = y;
|
invalidate();
|
|
return true;
|
|
}
|
return super.onTouchEvent(event);
|
|
}
|
|
|
/**
|
* 指定坐标是否在圆上,减了小圆圈半径
|
*/
|
private boolean isPointInPalette(float x, float y) {
|
return mPaletteScopeRegion.contains((int) x, (int) y);
|
}
|
|
|
/**
|
* RGB 0红 120 绿 240蓝
|
*/
|
private int getColorByPoint(float x, float y) {
|
final float centerX = mWidth * 0.5f;
|
final float centerY = mHeight * 0.5f;
|
final float radius = Math.min(centerX, centerY);
|
|
x = x - centerX;
|
y = y - centerY;
|
|
//色调0-360,饱和度0-1,亮度范围0-1
|
float[] hsv = {0, 0, 1};
|
//色调计算角度
|
hsv[0] = (float) (Math.atan2(y, -x) * 180f / Math.PI) + 180;
|
//饱和度,从圆心出发0~1
|
double r = Math.sqrt(x * x + y * y);
|
hsv[1] = Math.max(0f, Math.min(1f, (float) (r / radius)));
|
return Color.HSVToColor(hsv);
|
}
|
|
public void setCurrentColor(int mCurrentColor) {
|
if (mDelayAnim != null) {
|
mDelayAnim.cancel();
|
}
|
setCurrentColorInner(mCurrentColor);
|
|
}
|
|
private void setCurrentColorInner(int currentColor) {
|
this.mCurrentColor = currentColor;
|
post(new Runnable() {
|
@Override
|
public void run() {
|
Point point = getPointByColor(mCurrentColor);
|
touchX = point.x;
|
touchY = point.y;
|
invalidate();
|
}
|
});
|
|
|
}
|
|
public void setCurrentColorDelay(final int color) {
|
if (mDelayAnim != null) {
|
mDelayAnim.cancel();
|
}
|
|
//不相等才处理
|
if (mCurrentColor != color) {
|
|
mDelayAnim = ValueAnimator.ofFloat(0, 1);
|
mDelayAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
@Override
|
public void onAnimationUpdate(ValueAnimator animation) {
|
final float p = (float) animation.getAnimatedValue();
|
if (p == 1) {
|
setCurrentColorInner(color);
|
}
|
}
|
});
|
mDelayAnim.setStartDelay(300);
|
mDelayAnim.setDuration(100);
|
mDelayAnim.start();
|
}
|
|
|
}
|
|
|
public int getCurrentColor() {
|
return mCurrentColor;
|
}
|
|
public static String getHexCode(@ColorInt int color) {
|
int a = Color.alpha(color);
|
int r = Color.red(color);
|
int g = Color.green(color);
|
int b = Color.blue(color);
|
return String.format(Locale.getDefault(), "%02X%02X%02X%02X", a, r, g, b);
|
}
|
|
/**
|
* 通过颜色获取坐标
|
* 相对坐标
|
*/
|
private Point getPointByColor(@ColorInt int color) {
|
|
float[] hsv = {0, 0, 1};
|
Color.colorToHSV(color, hsv);
|
final float centerX = mWidth * 0.5f;
|
final float centerY = mHeight * 0.5f;
|
final float radius = Math.min(centerX, centerY);
|
|
final float d = hsv[1] * radius;
|
//转为弧度
|
double radians = Math.toRadians(hsv[0]);
|
|
|
int x = (int) (centerX + (float) (d * Math.cos(radians)));
|
int y = (int) (centerY - (float) (d * Math.sin(radians)));
|
|
return new Point(x, y);
|
}
|
|
/**
|
* 获取最近距离坐标点
|
*/
|
private Point getNearPoint(float x, float y, float centerX, float centerY, float parentRadius, float markRadius) {
|
Point point = new Point();
|
|
if (isPointInPalette(x, y)) {
|
point.x = (int) x;
|
point.y = (int) y;
|
} else {
|
//计算最近坐标
|
x = x - parentRadius;
|
y = y - parentRadius;
|
int r = (int) (parentRadius - markRadius);
|
//角度
|
float angle = (float) (Math.atan2(y, -x) * 180f / Math.PI) + 180;
|
//转为弧度
|
double radians = Math.toRadians(angle);
|
point.x = (int) (centerX + (float) (r * Math.cos(radians)));
|
point.y = (int) (centerY - (float) (r * Math.sin(radians)));
|
}
|
return point;
|
}
|
|
|
public void setMarkColor(int markColor) {
|
this.markColor = markColor;
|
}
|
|
private static final float WIDTH_DP_BASE = 360;
|
|
//==================根据密度适配=========================
|
public static int dp2pxAdapt(float dp) {
|
return dp2pxAdapt(dp, WIDTH_DP_BASE);
|
}
|
|
public static int dp2pxAdapt(float dp, float widthDpBase) {
|
DisplayMetrics dm = Resources.getSystem().getDisplayMetrics();
|
float density = dm.density;
|
float heightDP = dm.heightPixels / density;
|
float widthDP = dm.widthPixels / density;
|
float w = Math.min(widthDP, heightDP);
|
return (int) (dp * w / widthDpBase * density + 0.5f);
|
}
|
}
|