Android圆环颜色选择器
程序员文章站
2022-06-24 12:10:36
一个非常不错的颜色圆环选择器视图,由于项目需要自己写了一个圆环颜色选择器,部分代码来源与网络,如有相同敬请谅解。废话不多说,直接上源代码:1、在values下创建一个attr.xml文件,用于定义视图的xml属性: ...
一个非常不错的颜色圆环选择器视图,由于项目需要自己写了一个圆环颜色选择器,部分代码来源与网络,如有相同敬请谅解。废话不多说,直接上源代码:
1、在values下创建一个attr.xml文件,用于定义视图的xml属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RingColorPicker">
<!--默认角度-->
<attr name="angle" format="float"/>
<!--圆形选择器填充色-->
<attr name="markBackground" format="color|reference"/>
<!--圆形选择器边框颜色-->
<attr name="markStrokeColor" format="color|reference"/>
<!--圆形选择器描边-->
<attr name="isMarkStroke" format="boolean"/>
<!--圆环宽度-->
<attr name="ringWidth" format="dimension"/>
<!--选择器自动色-->
<attr name="isMarkAutoColor" format="boolean"/>
<!--扩散特效透明度-->
<attr name="spreadAlpha" format="integer"/>
<!--选择器描边宽度-->
<attr name="markStrokeWidth" format="dimension|reference"/>
<!--中心按钮图像资源-->
<attr name="srcCompat" />
<!--中心按钮图像透明度-->
<attr name="centerImageAlpha" format="integer"/>
<!--中心复选状态-->
<attr name="checked" format="boolean"/>
<!--当前指向的颜色-->
<attr name="currentColor" format="color|reference"/>
<!--过滤颜色-->
<attr name="tint" />
<!--视图样式-->
<attr name="colorPickerStyle" format="enum">
<enum name="MARK_RING_INNER" value="0"/>
<enum name="MARK_RING_OUTER" value="1"/>
<enum name="MARK_RING_DOWN_OUTER" value="2"/>
</attr>
</declare-styleable>
</resources>
2、这里面使用到了一个自定义颜色工具类来替换Color类,在Color类的基础上增加了部分转换,代码如下:
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorLong;
import androidx.annotation.IntRange;
import androidx.annotation.Size;
/**
* 颜色工具
*/
public class ColorUnit extends Color {
public ColorUnit(){
super();
}
/**
* 将RGB组件转换为HSV。
* <ul>
* <li>hsv[0]是色调([0..360[)</li>
* <li>hsv[1]已饱和\([0…1]\)</li>
* <li>hsv[2]是值\([0…1]\)</li>
* </ul>
* @param red 红色分量值([0..255])
* @param green 绿色分量值([0..255])
* @param blue 蓝色分量值([0..255])
* @param hsv 3元素数组,用于保存生成的HSV组件。
*/
public static void RGBToHSV(int red,int green, int blue,@Size(3) float hsv[]){
Color.RGBToHSV(red,green,blue,hsv);
}
/**
* 将RGB组件转换为HSV。
* <ul>
* <li>hsv[0]是色调([0..360[)</li>
* <li>hsv[1]已饱和([0…1]\)</li>
* <li>hsv[2]是值([0…1]\)</li>
* </ul>
* @param red 红色的分量([0..1])
* @param green 绿色的分量([0..1])
* @param blue 蓝色的分量([0..1])
* @param hsv 3元素数组,用于保存生成的HSV组件。
*/
public static void RGBToHSV(float red, float green, float blue, @Size(3) float hsv[]){
if(red<0) {
red = 0;
}else if(red>1){
red = 1;
}
if(green<0) {
green = 0;
}else if(green>1){
green = 1;
}
if(blue<0) {
blue = 0;
}else if(blue>1){
blue = 1;
}
Color.RGBToHSV((int)(red*255.0f),(int)(green*255.0f),(int)(blue*255.0f),hsv);
}
/**
* 将HSV组件转为RGB组件
* @param hsv 3元素数组。
* <ul>
* <li>hsv[0]是色调([0..360[)</li>
* <li>hsv[1]色饱和([0…1]\)</li>
* <li>hsv[2]是值([0…1]\)</li>
* </ul>
* @param rgb 3元素数组,用于保存生成的HSV组件。
* <ul>
* <li>rgb[0]颜色的红色分量([0..1])</li>
* <li>rgb[1] 颜色的绿色分量([0..1])</li>
* <li>rgb[2] 颜色的蓝色量([0..1])</li>
* </ul>
*/
public static void HSVToRGB(float hsv[], @Size(3) float rgb[]){
int color=Color.HSVToColor(hsv);
rgb[0]=Color.red(color);
rgb[1]=Color.green(color);
rgb[2]=Color.blue(color);
// Color.colorToHSV();
}
/**
* 将HSV组件转为RGB组件
* @param hue 是色调([0..360[)
* @param saturation 色饱和([0…1]\)
* @param value 亮度值([0…1]\)
* @param rgb 3元素数组,用于保存生成的HSV组件。
* <ul>
* <li>rgb[0]颜色的红色分量([0..1])</li>
* <li>rgb[1] 颜色的绿色分量([0..1])</li>
* <li>rgb[2] 颜色的蓝色量([0..1])</li>
* </ul>
*/
public static void HSVToRGB(float hue,float saturation,float value, @Size(3) float rgb[]){
float hsv[]={hue,saturation,value};
HSVToRGB(hsv,rgb);
}
/**
* 将HSV组件转换为ARGB颜色。Alpha设置为0xFF。
* @param hue 色调([0..360[)
* @param saturation 色饱和([0…1]\)
* @param value 亮度值([0…1]\)
* @return Argb颜色
*/
public static int HSVToColor(float hue,float saturation,float value){
float hsv[]={hue,saturation,value};
return Color.HSVToColor(hsv);
}
/**
* 将HSV组件转换为ARGB颜色。alpha分量通过不变。
* @param alpha 返回的argb颜色的alpha分量。
* @param hue 色调([0..360[)
* @param saturation 色饱和([0…1]\)
* @param value 亮度值([0…1]\)
* @return Argb颜色
*/
public static int HSVToColor(@IntRange(from = 0, to = 255) int alpha,float hue,float saturation,float value){
float hsv[]={hue,saturation,value};
return Color.HSVToColor(alpha,hsv);
}
/**
* 从范围([0..1])内的alpha、red、green、blue float组件返回一个颜色int。如果组件超出范围,则返回的颜色未定义。
* @param alpha 颜色的Alpha分量([0..1])
* @param red 颜色的红色分量([0..1])
* @param green 颜色的绿色分量([0..1])
* @param blue 颜色的蓝色量([0..1])
* @return
*/
@ColorInt
public static int argb(float alpha, float red, float green, float blue){
if(alpha<0) {
alpha = 0;
}else if(alpha>1){
alpha = 1;
}
if(red<0) {
red = 0;
}else if(red>1){
red = 1;
}
if(green<0) {
green = 0;
}else if(green>1){
green = 1;
}
if(blue<0) {
blue = 0;
}else if(blue>1){
blue = 1;
}
return ((int) (alpha * 255.0f + 0.5f) << 24) |
((int) (red * 255.0f + 0.5f) << 16) |
((int) (green * 255.0f + 0.5f) << 8) |
(int) (blue * 255.0f + 0.5f);
}
/**
* 从范围([0..1])内的红色、绿色、蓝色浮点组件返回一个颜色int。alpha组件隐式地为1.0(完全不透明)。如果组件超出范围,则返回的颜色未定义。
* @param red 颜色的红色分量([0..1])
* @param green 颜色的绿色分量([0..1])
* @param blue 颜色的蓝色量([0..1])
* @return
*/
@ColorInt
public static int rgb(float red, float green, float blue) {
if(red<0) {
red = 0;
}else if(red>1){
red = 1;
}
if(green<0) {
green = 0;
}else if(green>1){
green = 1;
}
if(blue<0) {
blue = 0;
}else if(blue>1){
blue = 1;
}
return 0xff000000 |
((int) (red * 255.0f + 0.5f) << 16) |
((int) (green * 255.0f + 0.5f) << 8) |
(int) (blue * 255.0f + 0.5f);
}
/**
* 返回以指定颜色长度编码的红色组件。返回值的范围取决于与指定颜色关联的颜色空间。可以通过调用{@link #colorSpace(long)}来查询颜色空间。
* @param color 要提取其红色通道的长颜色
* @return 具有由指定颜色的颜色空间定义的范围的浮点值
*
* @see #colorSpace(long)
* @see #green(long)
* @see #blue(long)
* @see #alpha(long)
*/
public static float red(@ColorLong long color) {
if ((color & 0x3fL) == 0L) return ((color >> 48) & 0xff) / 255.0f;
return toFloat((short) ((color >> 48) & 0xffff));
}
/**
* 返回以指定颜色长度编码的绿色组件。返回值的范围取决于与指定颜色关联的颜色空间。可以通过调用{@link #colorSpace(long)}来查询颜色空间。
* @param color 要提取其绿色通道的长颜色
* @return 具有由指定颜色的颜色空间定义的范围的浮点值
* @see #colorSpace(long)
* @see #red(long)
* @see #blue(long)
* @see #alpha(long)
*/
public static float green(@ColorLong long color) {
if ((color & 0x3fL) == 0L) return ((color >> 40) & 0xff) / 255.0f;
return toFloat((short) ((color >> 32) & 0xffff));
}
/**
* 返回以指定颜色长度编码的蓝色组件。返回值的范围取决于与指定颜色关联的颜色空间。可以通过调用{@link #colorSpace(long)}来查询颜色空间。
*
* @param color 要提取其蓝色通道的长颜色
* @return 具有由指定颜色的颜色空间定义的范围的浮点值
* @see #colorSpace(long)
* @see #red(long)
* @see #green(long)
* @see #alpha(long)
*/
public static float blue(@ColorLong long color) {
if ((color & 0x3fL) == 0L) return ((color >> 32) & 0xff) / 255.0f;
return toFloat((short) ((color >> 16) & 0xffff));
}
/**
* 返回以指定颜色长度编码的alpha组件。返回的值始终在范围([0..1])内。
* @param color 要提取其alpha通道的长颜色
* @return 范围为([0..1])的浮点值
* @see #colorSpace(long)
* @see #red(long)
* @see #green(long)
* @see #blue(long)
*/
public static float alpha(@ColorLong long color) {
// int c=Color.toArgb(color);
if ((color & 0x3fL) == 0L) return ((color >> 56) & 0xff) / 255.0f;
return ((color >> 6) & 0x3ff) / 1023.0f;
}
/**
* 将指定的长颜色转换为ARGB整型颜色。整型颜色始终位于{@link color space.Named#SRGB SRGB}颜色空间中。这意味着如果需要,将应用颜色空间转换。
* @param color 要转换的长颜色
* @return sRGB颜色空间中的ARGB颜色
*/
@ColorInt
public static int toArgb(@ColorLong long color) {
if ((color & 0x3fL) == 0L) return (int) (color >> 32);
float r = red(color);
float g = green(color);
float b = blue(color);
float a = alpha(color);
return ((int) (a * 255.0f + 0.5f) << 24) |
((int) (r * 255.0f + 0.5f) << 16) |
((int) (g * 255.0f + 0.5f) << 8) |
(int) (b * 255.0f + 0.5f);
}
/**
* 按指定透明度重新输出
* @param color 需要转换的颜色
* @param alpha 透明度
* @return 返回指定透明度的新颜色
*/
public static int toColor(int color,float alpha){
float red=Color.red(color)/255.0f;
float green=Color.green(color)/255.0f;
float blue=Color.blue(color)/255.0f;
return argb(alpha,red,green ,blue );
}
/**
* 按指定透明度重新输出
* @param color 需要转换的颜色
* @param alpha 透明度0-255
* @return 返回指定透明度的新颜色
*/
public static int toColor(int color,int alpha){
return argb(alpha,red(color),green(color),blue(color));
}
/**
* <p>将指定的半精度浮点值转换为单精度浮点值。
* @param h 要与此{@code half}对象表示的半精度值进行比较的半精度浮点值
* @return 如果{@code x}在数值上等于{@code y},则为{@code 0};如果{@code x}在数值上小于{@code y},则为小于{@code 0};如果{@code x}在数值上大于{@code y},则为大于{@code 0}
*/
public static float toFloat( short h) {
int bits = h & 0xffff;
int s = bits & 0x8000;
int e = (bits >>> 10) & 0x1f;
int m = (bits ) & 0x3ff;
int outE = 0;
int outM = 0;
if (e == 0) { // Denormal or 0
if (m != 0) {
// Convert denorm fp16 into normalized fp32
float o = Float.intBitsToFloat((126 << 23) + m);
o -= Float.intBitsToFloat((126 << 23));
return s == 0 ? o : -o;
}
} else {
outM = m << 13;
if (e == 0x1f) { // Infinite or NaN
outE = 0xff;
if (outM != 0) { // SNaNs are quieted
outM |= 0x400000;
}
} else {
outE = e - 15 + 127;
}
}
int out = (s << 16) | (outE << 23) | outM;
return Float.intBitsToFloat(out);
}
}
3、环形选择器源代码类:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import com.ble.konshine.util.ColorUnit;//这里引用路径工具自己ColorUnit实在的路径进行引用
import com.ble.konshine.R;//属性资源引用,路径根据自己的路径重新引用
public class RingColorPicker extends View {
private final static String TAG="RingColorPicker";
private final static int CENTER_CIRCLE_WIDTH=5;
/**长按超过0.3秒,触发长按事件*/
private static final int LONGPRESSTIME= 300;
/**宽度*/
private int width;
/**高度*/
private int height;
/**圆环的宽*/
private int RingWidth = 20;
/**颜色选择器样式*/
private PickerStyle colorPickerStyle=PickerStyle.MARK_RING_INNER;
/**内圆的半径*/
private float innerRadius;
/**外圆的半径*/
private float outerRadius;
/**圆的圆心坐标*/
private float circleX, circleY;
/**圆环的画笔*/
private Paint paintCircleRing;
/**圆形选择器*/
private Paint paintSelecter;
/**圆形选择器填充色*/
private int colorMarkFill =0xafffffff;
/**圆形选择器描边画笔*/
private Paint paintSelecterStroke;
/**圆形选择器描边*/
private boolean markStroke=false;
/**圆形选择器描边颜色*/
private int colorMarkStroke=0xff000000;
/**选择器圆心坐标*/
private float markPointX, markPointY;
/**默认角度*/
private float angle = 0;
/**选择器自动色*/
private boolean markAutoColor=true;
/**扩散效果透明度*/
private int spreadAlpha=128;
/**选择器圆点边框宽度*/
private int markStrokeWidth=1;
/**色环颜色的发散位置*/
private Shader shader;
/**中间圆画笔,用于显示当前选中的颜色*/
private Paint centerPaint;
/**中心图片*/
private Bitmap centerBitmap=null;
/**着色器颜色*/
private int tintColor=Color.BLACK;
/**着色*/
private boolean isTint=false;
/**图片着色器列表*/
private int[] tintArrayColor;
/**中心图片透明度*/
private int centerImageAlpha=255;
/**中心圆半径*/
private float centerRadius;
/**中心按钮复选状态*/
private boolean checked=false;
/**当前点颜色*/
private int currentColor;
/**中心位图画刷*/
private Paint centerBitmapPaint;
/**渐变色环参数:红、紫、蓝、青色、绿、黄、红*/
private final int[] mCircleColors =new int[] {
Color.RED ,
Color.YELLOW ,
Color.GREEN ,
Color.CYAN ,
Color.BLUE ,
Color.MAGENTA ,
Color.RED
};
/**冗长等级枚举*/
public enum PickerStyle{
/**选择器在圆环内%*/
MARK_RING_INNER(0),
/**选择器超出圆环%*/
MARK_RING_OUTER(1),
/**选择器按下是超出圆环*/
MARK_RING_DOWN_OUTER(2);
private int style;
/**选择器样式*/
PickerStyle( int style){
this.style=style;
}
/**获取选择器样式*/
public int getStyle() {
return this.style;
}
}
/**在圆环上按下*/
private boolean isRingDown=false;
/**在选择器上按下*/
private boolean isMarkPointRangeDown=false;
/**用户改变*/
private boolean isFromUser=false;
/**中心按钮按下状态*/
private boolean isButtonClick=false;
/**上一次点击的的坐标*/
private float lastX,lastY;
/**计时器,计时点击时长*/
private Timer timer;
/**长按时间处理*/
private TimerTask timerTaskLongDown;
/**用于存放改变前的角度*/
private float oleAngle=0;
/**用于标识是否使用了长按*/
private boolean isLongClick=false;
/**
* 当进颜色更改时通知客户端的回调。这包括用户通过触摸手势或箭头键/轨迹球发起的更改,以及以编程方式发起的更改。
*/
public interface OnRingColorPickerChangeListener {
/**
* 改变通知。
* 客户机可以使用from user参数将用户发起的更改与以编程方式发生的更改区分开来。
* @param ringColorPicker 以改变的RingColorPicker对象
* @param angle 改变的角度值
* @param fromUser 如果进度更改是由用户启动的,则为True。
*/
void onChangeListener(RingColorPicker ringColorPicker,float angle,boolean fromUser);
/**
* 通知用户已开始触摸手势。客户端可能希望使用此选项来禁用推进ringColorPicker。
* @param ringColorPicker 开始触摸手势的RingColorPicker
*/
void onStartTrackingTouch(RingColorPicker ringColorPicker);
/**
* 通知用户已完成触摸手势。客户端可能希望使用此选项重新启用ringColorPicker。
* @param ringColorPicker 停止触摸手势的RingColorPicker
*/
void onStopTrackingTouch(RingColorPicker ringColorPicker);
}
/**
* 颜色选择器中心按钮的选中状态更改时要调用的回调的接口定义。
*/
public interface OnCheckedChangeListener{
/**
* 当颜色选择器中心按钮的选中状态更改时调用。
* @param colorPicker 状态已更改的颜色选择器视图。
* @param isChecked 新选中状态。
* @param fromUser 如果进度更改是由用户启动的,则为True。
*/
void onCheckedChanged(RingColorPicker colorPicker, boolean isChecked,boolean fromUser);
}
/**定义颜色选择器颜色选择更改通知变量*/
private OnRingColorPickerChangeListener onRingColorPickerChangeListener;
/**定义中心按钮状态改变通知变量*/
private OnCheckedChangeListener onCheckedChangeListener;
/**d定义中心按钮单击事件*/
private OnClickListener onClickListener;
/**定义中心按钮长按事件*/
private OnLongClickListener onLongClickListener;
/**
* 构造函数
* @param context 应用上下文
*/
public RingColorPicker(Context context) {
this(context,null);
}
/**
* 构造函数
* @param context 应用上下文
* @param attrs 控件属性集对象
*/
public RingColorPicker(Context context, @Nullable AttributeSet attrs) {
this(context,attrs,0);
}
/**
* 构造函数
* @param context 应用上下文
* @param attrs 控件属性集对象
* @param defStyleAttr 默认样式
*/
public RingColorPicker(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.RingColorPicker);
this.angle=typedArray.getFloat(R.styleable.RingColorPicker_angle,this.angle);
this.colorMarkFill =typedArray.getColor(R.styleable.RingColorPicker_markBackground,this.colorMarkFill );
this.colorMarkStroke=typedArray.getColor(R.styleable.RingColorPicker_markStrokeColor,this.colorMarkStroke);
this.markStroke=typedArray.getBoolean(R.styleable.RingColorPicker_isMarkStroke, this.markStroke);
this.RingWidth=typedArray.getDimensionPixelOffset(R.styleable.RingColorPicker_ringWidth,dp2px(context, this.RingWidth));
this.markAutoColor=typedArray.getBoolean(R.styleable.RingColorPicker_isMarkAutoColor,this.markAutoColor);
this.spreadAlpha=typedArray.getInt(R.styleable.RingColorPicker_spreadAlpha,this.spreadAlpha);
this.markStrokeWidth=typedArray.getDimensionPixelOffset(R.styleable.RingColorPicker_markStrokeWidth,dp2px(context,this.markStrokeWidth));
int resid=typedArray.getResourceId(R.styleable.RingColorPicker_srcCompat,0); //获取 图片资源id
if(resid!=0) {
this.centerBitmap = VectorDrawableToBitmap(resid); //从资源ID矢量图形转为位图
if (this.centerBitmap == null) {
this.centerBitmap = BitmapFactory.decodeResource(getResources(), resid);//从图片资源中获取位图
}
}
centerImageAlpha=typedArray.getInt(R.styleable.RingColorPicker_centerImageAlpha,centerImageAlpha);
isTint=typedArray.getResourceId(R.styleable.RingColorPicker_tint,0)!=0;
if(isTint) {
tintColor = typedArray.getColor(R.styleable.RingColorPicker_tint, tintColor);
}
checked=typedArray.getBoolean(R.styleable.RingColorPicker_checked,checked);
// currentColor=typedArray.getColor(R.styleable.RingColorPicker_currentColor,0);
String hexColor=typedArray.getString(R.styleable.RingColorPicker_currentColor); //通过字符串方式获取16进制颜色字符串
if(hexColor!=null) { //判断字符串是否为空
//计算当前颜色,
float hsv[] = new float[3];
currentColor=Color.parseColor(hexColor);
ColorUnit.colorToHSV(currentColor, hsv);//得到当前显示的颜色
this.angle=hsv[0]+90;
if(this.angle>360) this.angle-=360;
}else{
//将当前选择器圆点角度转为hsv颜色的标准角度
float tempAngle=this.angle-90;
if(tempAngle<0) tempAngle+=360.0f;
currentColor= ColorUnit.HSVToColor(255,tempAngle,1,1);//这里的角度必须要减90度,因为hsv的0度颜色为红色
}
int mPickerStyle= typedArray.getInteger(R.styleable.RingColorPicker_colorPickerStyle,0);
if(mPickerStyle==0){
this.colorPickerStyle=PickerStyle.MARK_RING_INNER;
}else if(mPickerStyle==1){
this.colorPickerStyle=PickerStyle.MARK_RING_OUTER;
}else if(mPickerStyle==2){
this.colorPickerStyle=PickerStyle.MARK_RING_DOWN_OUTER;
}
init();
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// RingWidth = dp2px(getContext(), 20);
width = getMeasuredWidth();
height = getMeasuredHeight();
//四边最保留区域(非绘图区,最少保留4给像素)
int paddingLeft,paddingRight;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
paddingLeft=(getPaddingStart()==0?getPaddingLeft():getPaddingStart())+4;
paddingRight=(getPaddingEnd()==0?getPaddingRight():getPaddingEnd())+4;
}else{
paddingLeft=getPaddingLeft()+4;
paddingRight=getPaddingRight()+4;
}
int paddingTop=getPaddingTop()+4;
int paddingBottom=getPaddingBottom()+4;
if(colorPickerStyle==PickerStyle.MARK_RING_OUTER ||colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER){
paddingLeft+=RingWidth/2;
paddingRight+=RingWidth/2;
paddingTop+=RingWidth/2;
paddingBottom+=RingWidth/2;
}
int size = ((width-paddingLeft-paddingRight) > (height-paddingTop-paddingBottom)) ? height-paddingTop-paddingBottom : width-paddingLeft-paddingRight; //选择最小
circleX =paddingLeft+(width-paddingLeft-paddingRight)/2;//(width+getPaddingLeft()-getPaddingRight()) / 2; //确定圆的x坐标中心点
circleY = paddingTop+(height-paddingTop-paddingBottom )/2;//height / 2; //确定圆的Y坐标中心点
//分辨率适配:获取圆环的宽度 圆环的半径 内部圆的半径
outerRadius=size/2;//-dp2px(getContext(),4);//-barWidth*2;
innerRadius=outerRadius-RingWidth;
shader=new SweepGradient(circleX, circleY, mCircleColors, null);//角度渐变着色器,颜色平均分配
paintCircleRing.setShader(shader);//设置着色器
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/***********************画色环*****************************/
Path path=new Path();
RectF outerRect=new RectF(circleX-outerRadius,circleY-outerRadius,circleX+outerRadius,circleY+outerRadius);
RectF innerRect=new RectF(circleX-innerRadius,circleY-innerRadius,circleX+innerRadius,circleY+innerRadius);
//这里内圆和外圆的开始角一定要错开,否则路径无法闭合,填充出来的就不是圆环
path.addArc(outerRect,0,360);
path.arcTo(innerRect,359,-360);
path.close();
canvas.drawPath(path,paintCircleRing);
/******************* 绘制颜色选择器*************************/
setInitMarkToXY(this.angle);
float frameRadius;
if(colorPickerStyle==PickerStyle.MARK_RING_INNER||colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER){
frameRadius =RingWidth/2;
}else{
frameRadius =RingWidth;
}
if(this.markAutoColor) {
paintSelecter.setColor(interpCircleColor(mCircleColors, this.angle));
}
if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER && isMarkPointRangeDown){
Paint spreadPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
spreadPaint.setStyle(Paint.Style.FILL);
int spreadColor;
if(this.markAutoColor) {
spreadColor=interpCircleColor(mCircleColors, this.angle);
}else{
spreadColor=colorMarkFill;
}
Shader mShader = new RadialGradient(markPointX, markPointY, RingWidth, new int[]{spreadColor, ColorUnit.toColor(spreadColor,30)}, null,Shader.TileMode.CLAMP);
spreadPaint.setShader(mShader);
canvas.drawCircle(markPointX, markPointY, RingWidth, spreadPaint); //绘制半透明扩散
}else{
canvas.drawCircle(markPointX, markPointY, frameRadius, paintSelecter);//绘制选择器圆点
}
if(markStroke||colorPickerStyle!=PickerStyle.MARK_RING_OUTER) {//绘制选择器边框
float radius=frameRadius-markStrokeWidth/2;//重新计算圆的半径,用于解决线宽向内扩充的问题
canvas.drawCircle(markPointX, markPointY, radius, paintSelecterStroke); //绘制选择器圆点边框
}
/*********************绘制中心按钮*************************/
centerRadius=innerRadius/2;
if(checked) { //复选状态为选择状态
centerPaint.setShader(new RadialGradient(circleX, circleY, innerRadius, new int[]{currentColor, 0x00ffffff}, null, Shader.TileMode.CLAMP));
centerPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(circleX, circleY, innerRadius, centerPaint);//画中心圆
centerPaint.setShader(null);
centerPaint.setColor(currentColor);
canvas.drawCircle(circleX, circleY, centerRadius, centerPaint);//画中心圆
}
//绘制中心按钮边框
centerPaint.setStyle(Paint.Style.STROKE);
centerPaint.setColor(0xffffffff);
centerPaint.setStrokeWidth(3);
canvas.drawCircle(circleX,circleY, centerRadius, centerPaint);//画中心圆边框
if(centerBitmap!=null) {
int imgRadius= (int) (centerRadius / 2);
if(tintArrayColor!=null && tintArrayColor.length>1) {
centerBitmap = getGradientBitmap(centerBitmap,tintArrayColor);
canvas.drawBitmap(centerBitmap, null, new Rect((int) (circleX - imgRadius), (int) (circleY-imgRadius), (int)(circleX + imgRadius), (int) (circleY+imgRadius)), null);
}else{
canvas.drawBitmap(centerBitmap, null, new Rect((int) (circleX - imgRadius), (int) (circleY-imgRadius), (int)(circleX + imgRadius), (int) (circleY+imgRadius)), isTint?centerBitmapPaint:null);//centerBitmapPaint
}
}
// Paint paint = new Paint();
// paint.setTextSize(25);
// paint.setColor(Color.RED);
//
// paint.setFlags(Paint. UNDERLINE_TEXT_FLAG);
// paint.setColor(Color.GREEN);
// canvas.drawText("My Underline Text", 50, 140, paint);
//canvas.drawText("角度:"+this.angle,20,20,centerPaint);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (isPointRange(x,y) || isMarkPointRange(x, y)) { //如果触摸坐标在圆环或颜色选择器上时
getParent().requestDisallowInterceptTouchEvent(true); //请求请求所有的视图件禁止接收触摸事件
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: //触摸按下
//判断触摸按下的坐标是否在圆环上
if (isPointRange(x,y)){
if(onRingColorPickerChangeListener!=null){
onRingColorPickerChangeListener.onStartTrackingTouch(this);
}
isRingDown=true; //将标志改为触摸按下圆环
//判断触摸按下的坐标是否非选择器上,不在选择器上就执行旋转操作
if (!isMarkPointRange(x, y)) {
this.isFromUser=true;
if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER)
isMarkPointRangeDown=true;
setAngle(x, y); //设置旋转角度
}else{
isMarkPointRangeDown=true;
if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER)
invalidate();
}
}else{
isRingDown=false; //将标志设置未非圆环上按下
if (isMarkPointRange(x, y)) { //这里用于处理选择器圆点大于圆环宽度的情况
isMarkPointRangeDown=true;
if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER)
invalidate();
}
}
if(isCenterButton(x,y)) {
timer=new Timer();//长按计时器
timerTaskLongDown=new TimerTask() {
@Override
public void run() {
isButtonClick=false;
if(onLongClickListener!=null){
isLongClick=onLongClickListener.onLongClick(RingColorPicker.this); //触发长按事件
}
}
};
isButtonClick=true;
timer.schedule(timerTaskLongDown,LONGPRESSTIME,1000*60*60*24);
//记录上次点击的位置,用来进行移动的模糊处理
lastX=x;
lastY=y;
}
break;
case MotionEvent.ACTION_MOVE: //触摸移动
if(isRingDown) { //如果为圆环按下状态
if(isMarkPointRangeDown){ //如果为选择器按下状态
this.isFromUser=true;
setAngle(x, y); //设置旋转角度
}else {
if (isMarkPointRange(x, y)) { //判断触摸按下的坐标是否非选择器上
isMarkPointRangeDown=true; //将标志改为选择器按下状态
if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER)
invalidate();
}
}
}else{
if(isMarkPointRangeDown){ //处理选择器圆点大于圆环宽度的情况
this.isFromUser=true;
setAngle(x, y); //设置旋转角度
}
}
//处理长按判断
if(isButtonClick) {
if (Math.abs(lastX - x) > 20 || Math.abs(lastY - y) > 20) { //判断是否移动
isButtonClick=false;
//取消计时
if(timerTaskLongDown!=null) timerTaskLongDown.cancel();
if(timer!=null) timer.cancel();
}else{
return true;
}
}
break;
case MotionEvent.ACTION_UP://触摸弹起
if(isRingDown||isMarkPointRangeDown){
if(onRingColorPickerChangeListener!=null){
onRingColorPickerChangeListener.onStopTrackingTouch(this);
}
}
//if(colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER)
//计算当前颜色,
float hsv[]=new float[3];
ColorUnit.colorToHSV(currentColor,hsv);//得到当前显示的颜色
//将当前选择器圆点角度转为hsv颜色的标准角度
float tempAngle=this.angle-90;
if(tempAngle<0) tempAngle+=360.0f;
//将当前hsv代表的颜色替换角度后重新生成当前新颜色(这样的目的是只改变色调,饱和度和亮度保存不变)
currentColor= ColorUnit.HSVToColor(255,tempAngle,hsv[1],hsv[2]);
if(isCenterButton(x,y) && !isLongClick){
setChecked(!checked,true); //将状态取反
if(onClickListener!=null){ //触发单击事件
onClickListener.onClick(this);
}
}
invalidate();
//取消计时
if(timerTaskLongDown!=null) timerTaskLongDown.cancel();
if(timer!=null) timer.cancel();
isRingDown=false;
isMarkPointRangeDown=false;
isButtonClick=false;
isLongClick=false;
break;
case MotionEvent.ACTION_CANCEL: //取消操作
Log.e("onTouchEvent","取消操作");
break;
}
return true;
}
/**************************公共属性及方法******************************/
/**
* 设置侦听器以接收RingColorPicker更改的通知。还提供用户在RingColorPicker中启动和停止触摸手势的通知。
* @param listener 通知侦听器
*/
public void setOnRingColorPickerChangeListener(@Nullable OnRingColorPickerChangeListener listener){
this.onRingColorPickerChangeListener = listener;
}
/**
* 注册此按钮的选中状态更改时要调用的回调。
* @param listener 调用选中状态更改的回调
*/
public void setOnCheckedChangeListener( @Nullable OnCheckedChangeListener listener){
this.onCheckedChangeListener=listener;
}
/**
* 注册颜色选择器中心按钮单击事件
* @param onClickListener 将运行的回调
*/
@Override
public void setOnClickListener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
/**
* 注册颜色选择器中心按钮长按事件
* @param onLongClickListener 将运行的回调
*/
@Override
public void setOnLongClickListener(OnLongClickListener onLongClickListener) {
this.onLongClickListener = onLongClickListener;
}
/**
* 设置选择器再圆环的角度
* @param angle 角度
*/
public void setAngle(float angle) {
this.angle = angle;
this.isFromUser=false;
invalidate();
ImageView imageView;
}
/**获取选择器再圆环上的角度*/
public float getAngle() {
return angle;
}
/**
* 设置圆环宽度
* @param ringWidth
*/
public void setRingWidth(int ringWidth) {
RingWidth = dp2px(getContext(),ringWidth);
invalidate();
}
/**获取圆环宽度*/
public int getRingWidth() {
return RingWidth;
}
/**
* 设置选择器背景颜色
* @param color 颜色值
*/
public void setMarkBackground(int color){
this.colorMarkFill =color;
paintSelecter.setColor(colorMarkFill );
invalidate();
}
/**
* 设置选择器背景颜色
* @param color Color颜色对象
*/
public void setMarkBackground(Color color){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setMarkBackground(color.toArgb());
}
}
/**
* 设置选择器背景颜色
* @param colorString 16进制颜色字符串。如"#RRGGBB 或 #AARRGGBB"
*/
public void setMarkBackground(String colorString){
try {
int color=Color.parseColor(colorString);
setMarkBackground(color);
} catch (Exception e) {
Log.e("setSelecterBackground",e.getMessage());
}
}
/**获取选择器背景色*/
public int getMarkBackground(){
return colorMarkFill ;
}
/**
* 设置选择器边框杨色
* @param color 颜色值
*/
public void setMarkStrokeColor(int color){
this.colorMarkStroke=color;
paintSelecterStroke.setColor(colorMarkStroke);
invalidate();
}
/**
* 设置选择器边框杨色
* @param color Color颜色对象
*/
public void setMarkStrokeColor(Color color){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.setMarkStrokeColor( color.toArgb());
}
}
/**
* 设置选择器边框杨色
* @param colorString 16进制颜色字符串。如"#RRGGBB 或 #AARRGGBB"
*/
public void setMarkStrokeColor(String colorString){
try {
int color=Color.parseColor(colorString);
setMarkStrokeColor(color);
} catch (Exception e) {
Log.e("setSelecterStroke",e.getMessage());
}
}
/**获取选择器边框颜色*/
public int getMarkStrokeColor(){
return colorMarkStroke;
}
/**
* 设置选择器边框(只对ColorPickerStyle=MARK_RING_OUTER有效,另外两种样式必须具有边框)
* @param stroke
*/
public void setMarkStroke(boolean stroke){
this.markStroke=stroke;
invalidate();
}
/**获取选择器边框*/
public boolean isMarkStroke() {
return markStroke;
}
/**
* 设置选择器样式
* @param colorPickerStyle PickerStyle枚举
*/
public void setColorPickerStyle(PickerStyle colorPickerStyle) {
this.colorPickerStyle = colorPickerStyle;
////////////////////////////重新初始化以下参数/////////////////////////////////////////////////
//四边最保留区域(非绘图区,最少保留4给像素)
int paddingLeft,paddingRight;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
paddingLeft=(getPaddingStart()==0?getPaddingLeft():getPaddingStart())+4;
paddingRight=(getPaddingEnd()==0?getPaddingRight():getPaddingEnd())+4;
}else{
paddingLeft=getPaddingLeft()+4;
paddingRight=getPaddingRight()+4;
}
int paddingTop=getPaddingTop()+4;
int paddingBottom=getPaddingBottom()+4;
if(colorPickerStyle==PickerStyle.MARK_RING_OUTER ||colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER){
paddingLeft+=RingWidth/2;
paddingRight+=RingWidth/2;
paddingTop+=RingWidth/2;
paddingBottom+=RingWidth/2;
}
int size = ((width-paddingLeft-paddingRight) > (height-paddingTop-paddingBottom)) ? height-paddingTop-paddingBottom : width-paddingLeft-paddingRight; //选择最小
circleX =paddingLeft+(width-paddingLeft-paddingRight)/2;//(width+getPaddingLeft()-getPaddingRight()) / 2; //确定圆的x坐标中心点
circleY = paddingTop+(height-paddingTop-paddingBottom )/2;//height / 2; //确定圆的Y坐标中心点
//分辨率适配:获取圆环的宽度 圆环的半径 内部圆的半径
outerRadius=size/2;//-dp2px(getContext(),4);//-barWidth*2;
innerRadius=outerRadius-RingWidth;
shader=new SweepGradient(circleX, circleY, mCircleColors, null);//角度渐变着色器
paintCircleRing.setShader(shader);//设置着色器
invalidate();
}
/**获取选择器样式*/
public PickerStyle getColorPickerStyle() {
return colorPickerStyle;
}
/**
* 使用选择器自动色
* @param autoColor
*/
public void setMarkAutoColor(boolean autoColor){
this.markAutoColor=autoColor;
invalidate();
}
/**获取选择器自动颜色状态 */
public boolean isMarkAutoColor() {
return markAutoColor;
}
/**
* 设置扩散效果透明度
* @param alpha 透明度(0-255之间)
*/
public void setSpreadAlpha(int alpha) {
if(alpha<0)
alpha=0;
else if(alpha>255)
alpha=255;
this.spreadAlpha = alpha;
invalidate();
}
/**
* 设置扩散效果透明度
* @param alpha 透明度(0-1之间)
*/
public void setSpreadAlpha(float alpha) {
if(alpha<0)
alpha=0;
else if(alpha>1)
alpha=1;
setSpreadAlpha((int) (alpha*255));
}
/**获取扩散效果透明度*/
public int getSpreadAlpha() {
return spreadAlpha;
}
/**
* 设置选择器圆点边框宽度
* @param markStrokeWidth
*/
public void setMarkStrokeWidth(int markStrokeWidth) {
this.markStrokeWidth = dp2px(getContext(),markStrokeWidth);
paintSelecterStroke.setStrokeWidth(this.markStrokeWidth);
invalidate();
}
/**获取选择器圆点边框宽度*/
public int getMarkStrokeWidth() {
return markStrokeWidth;
}
/**
* 设置中心图片位图
* @param bm 位图
*/
public void setCenterImageBitmap(Bitmap bm){
centerBitmap=bm;
invalidate();
}
/**
* 设置中心图片Drawable
* @param drawable
*/
public void setCenterImageDrawable(Drawable drawable){
setCenterImageBitmap(DrawableToBitmap(drawable));
}
/**
* 设置中心图片资源ID
* @param resId 资源id
*/
public void setCenterImageResource(int resId){
setCenterImageBitmap(BitmapFactory.decodeResource(getResources(),resId));
}
/**
* 设置中心图片图标
* @param icon 图标
*/
public void setImageIcon(Icon icon){
if ( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ) {
BitmapDrawable bd=(BitmapDrawable) icon.loadDrawable(this.getContext());
setCenterImageBitmap(bd.getBitmap());
}
}
/**
* 设置中心图片uri地址
* @param uri
*/
public void setCenterImageURI(Uri uri){
try {
Bitmap bm= MediaStore.Images.Media.getBitmap(this.getContext().getContentResolver(), uri);
setCenterImageBitmap(bm);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,e.getMessage());
}
}
/**获取中心图标位图*/
public Bitmap getCenterImageBitmap(){
return centerBitmap;
}
/**
* 设置中心图片透明度
* @param alpha 透明度(0-255)
*/
public void setCenterImageAlpha(int alpha){
centerImageAlpha=alpha;
centerBitmapPaint .setAlpha( this.centerImageAlpha);
invalidate();
}
/**获取中心图片透明度*/
public float getCenterImageAlpha() {
return centerImageAlpha;
}
/**
* 设置中心按钮复选状态
* @param checked 选择状态
*/
public void setChecked(boolean checked) {
setChecked(checked,false);
invalidate();
}
/**获取中心按钮选择状态*/
public boolean isChecked() {
return checked;
}
/**
* 设置着色器颜色
* @param tintColor
*/
public void setTintColor(int tintColor) {
this.tintColor = tintColor;
centerBitmapPaint.setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
isTint=true;
invalidate();
}
/**
* 设置着色器颜色
* @param tintColor
*/
public void setTintColor(Color tintColor) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if(tintColor!=null) {
setTintColor(tintColor.toArgb());
}else{
isTint=false;
invalidate();
}
}
}
/**
* 设置着色器颜色
* @param colorString
*/
public void setTintColor(String colorString) {
try {
setTintColor(Color.parseColor(colorString));
} catch (Exception e) {
Log.e("setTintColor",e.getMessage());
isTint=false;
invalidate();
}
}
/**获取着色器颜色**/
public int getTintColor() {
return tintColor;
}
/**
* 设置图片着色器渐变色
* @param arrayColor
*/
public void setTintArrayColor(int[] arrayColor){
tintArrayColor=arrayColor;
invalidate();
}
/**获取着色器渐变色*/
public int[] getTintArrayColor() {
return tintArrayColor;
}
/**
* 设置当前颜色
* @param color 需要改变的当前颜色
*/
public void setCurrentColor(int color) {
this.currentColor = color;
float hsv[]=new float[3];
ColorUnit.colorToHSV(this.currentColor,hsv);//得到当前显示的颜色
this.angle=hsv[0]+90;
if(this.angle>360) this.angle-=360;
this.isFromUser=false;
invalidate();
}
/**
* 设置当前颜色
* @param color 需要改变的当前颜色
*/
public void setCurrentColor(Color color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setCurrentColor(color.toArgb());
}
}
/**
* 设置当前颜色
* @param colorString 需要改变的当前颜色
*/
public void setCurrentColor(String colorString) {
try {
setCurrentColor(Color.parseColor(colorString));
} catch (Exception e) {
Log.e("setCurrentColor",e.getMessage());
}
}
/**
* 通过HSV设置当前颜色
* @param hsv 3元素数组。
* <ul>
* <li>hsv[0]是色调([0..360[)</li>
* <li>hsv[1]色饱和([0…1]\)</li>
* <li>hsv[2]是值([0…1]\)</li>
* </ul>
*/
public void setCurrentColor(float[] hsv){
setCurrentColor(ColorUnit.HSVToColor(hsv));
}
/**
* 通过HSV设置当前颜色
* @param hue 色调([0..360[)
* @param saturation 色饱和([0…1]\)
* @param value 亮度值([0…1]\)
*/
public void setCurrentColor(float hue,float saturation,float value){
setCurrentColor(ColorUnit.HSVToColor(hue,saturation,value));
}
/**获取当前颜色**/
public int getCurrentColor() {
return currentColor;
}
/**
* 获取渐变混色位图
* @param drawableId 资源ID
* @param colors 渐变颜色数组
* @return
*/
public Bitmap getGradientBitmap( int drawableId, int[] colors) {
//android不允许直接修改res里面的图片,所以要用copy方法
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), drawableId)
.copy(Bitmap.Config.ARGB_8888, true);
addGradient(bitmap, colors);
return bitmap;
}
/**
* 获取渐变混色位图
* @param bitmap 需要渐变混色的位图
* @param colors 渐变颜色数组
* @return
*/
public Bitmap getGradientBitmap( Bitmap bitmap, int[] colors) {
Bitmap tempbitmap=bitmap.copy(Bitmap.Config.ARGB_8888, true);
addGradient(tempbitmap, colors);
return tempbitmap;
}
/***********************所有方法****************************/
/**
* 初始化
*/
private void init() {
// 渐变色环参数
paintCircleRing = new Paint(Paint.ANTI_ALIAS_FLAG);
paintCircleRing.setAntiAlias(true);
paintCircleRing.setStyle(Paint.Style.FILL);
//选择器
paintSelecter = new Paint(Paint.ANTI_ALIAS_FLAG);
paintSelecter.setColor(colorMarkFill );
paintSelecter.setAntiAlias(true);
paintSelecter.setStrokeWidth(10);
//选择器描边画笔
// if(markStroke||colorPickerStyle!=PickerStyle.MARK_RING_OUTER) {//绘制选择器边框
paintSelecterStroke = new Paint(Paint.ANTI_ALIAS_FLAG);//创建画笔,并边缘平滑
paintSelecterStroke.setColor(colorMarkStroke);
paintSelecterStroke.setStyle(Paint.Style.STROKE);
paintSelecterStroke.setStrokeWidth(this.markStrokeWidth);
// }
//初始化中心圆的Paint对象
centerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerPaint.setAntiAlias(true);
// centerPaint.setColor(centerCircleColor);
centerPaint.setStrokeWidth(CENTER_CIRCLE_WIDTH);
centerBitmapPaint = new Paint();
centerBitmapPaint .setStyle( Paint.Style.STROKE );
centerBitmapPaint .setAlpha( this.centerImageAlpha);
centerBitmapPaint.setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
}
/**
* dp转像素
* @param context 应用上下文
* @param dpVal 需要转换的dp值
* @return 返回像素未单位的值
*/
private static int dp2px(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.getResources().getDisplayMetrics());
}
/**
* 设置选择器坐标
* @param angle 选择器实在的坐标
*/
private void setInitMarkToXY(float angle) {
markPointX = (float) (circleX + (outerRadius- RingWidth/2)* Math.sin(angle * Math.PI / 180));
markPointY = (float) (circleY - (outerRadius- RingWidth/2) * Math.cos(angle * Math.PI / 180));
if(onRingColorPickerChangeListener!=null && oleAngle!=angle){
onRingColorPickerChangeListener.onChangeListener(this,this.angle,this.isFromUser);
oleAngle=angle;
}
this.isFromUser=false;
}
/**
* 返回指定坐标是否再选择器上
* @param x
* @param y
* @return true 在选择器上,false 不在选择器上
*/
private boolean isMarkPointRange(float x, float y) {
float centralOffset= (float) Math.sqrt(Math.pow(x-markPointX,2)+Math.pow(y-markPointY,2));//计算指定点到圆心偏移量
if(colorPickerStyle==PickerStyle.MARK_RING_INNER||colorPickerStyle==PickerStyle.MARK_RING_DOWN_OUTER) {
return centralOffset <= (RingWidth / 2);
}else{
return centralOffset <= RingWidth ;
}
}
/**
* 指定坐标是否在中心按钮上
* @param x
* @param y
* @return true 在按钮上,false 不在
*/
private boolean isCenterButton(float x,float y){
float centralOffset= (float) Math.sqrt(Math.pow(x-circleX,2)+Math.pow(y-circleY,2));//计算指定点到圆心偏移量
return centralOffset<=innerRadius/2;
}
/**
* 指定坐标是否在圆环上
* @param x
* @param y
* @return true 再圆环上,false 不在圆环上
*/
private boolean isPointRange(float x,float y){
float centralOffset= (float) Math.sqrt(Math.pow(x-circleX,2)+Math.pow(y-circleY,2));//计算指定点到圆心偏移量
return centralOffset>=innerRadius && centralOffset<=outerRadius;
}
/**
* 根据指定坐标设置选择器旋转角度
* @param x
* @param y
*/
private void setAngle(float x,float y) {
markPointX = (float) (circleX + outerRadius * Math.cos(Math.atan2(x - circleX, circleY - y) - (Math.PI / 2)));
markPointY = (float) (circleY + outerRadius * Math.sin(Math.atan2(x - circleX, circleY - y) - (Math.PI / 2)));
float degrees = (float) ((float) ((Math.toDegrees(Math.atan2(x - circleX, circleY - y)) + 360.0)) % 360.0);
// 注意:为负数要加360°
if (degrees < 0)
degrees += 2 * Math.PI;
//角度四舍五入
this.angle = Math.round(degrees);
invalidate(); //刷新ui
}
/**
* 设置中心按钮复选状态
* @param checked 选择状态
* @param isFromUser 用户改变
*/
private void setChecked(boolean checked,boolean isFromUser) {
this.checked = checked;
if(onCheckedChangeListener!=null){
onCheckedChangeListener.onCheckedChanged(this,checked,isFromUser);
}
}
/**
* 获取圆环上颜色
* @param colors 圆环上面使用到的颜色数组
* @param angle 角度
* @return 返回int颜色
*/
private int interpCircleColor(int colors[], float angle) {
angle -= 90;
if (angle < 0)
angle += 360;
float p = angle * (colors.length - 1) / 360;
int i = (int) p;
p -= i;
int c0 = colors[i];
int c1 = colors[i + 1];
int a = ave(Color.alpha(c0), Color.alpha(c1), p);
int r = ave(Color.red(c0), Color.red(c1), p);
int g = ave(Color.green(c0), Color.green(c1), p);
int b = ave(Color.blue(c0), Color.blue(c1), p);
return Color.argb(a, r, g, b);
}
private int ave(int s, int d, float p) {
return s + Math.round(p * (d - s));
}
/**
* Drawable转位图
* @param drawable
* @return
*/
private Bitmap DrawableToBitmap(Drawable drawable){
BitmapDrawable bd=null;
try {
bd = (BitmapDrawable) drawable;
} catch (Exception e) {
e.printStackTrace();
}
if(bd!=null) {
return bd.getBitmap();
}else{
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height,
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0,0,width,height);
drawable.draw(canvas);
return bitmap;
}
}
/**
* 从资源ID中的矢量图转位图
* @param resId 资源id
* @return
*/
private Bitmap VectorDrawableToBitmap(int resId){
Drawable drawable = ContextCompat.getDrawable(getContext(),resId);
drawable = (DrawableCompat.wrap(drawable)).mutate();
return DrawableToBitmap(drawable);
}
/**
* 给位图添加线形着色
* @param originalBitmap 需要着色的旧位图
* @param colors 颜色数组,如果为null或数组长度为0,默认着#ff9900色
* @return 返回着色后的位图
*/
private Bitmap addGradient(Bitmap originalBitmap, int[] colors) {//给originalBitmap着渐变色
if (colors == null || colors.length == 0) {//默认色处理
colors = new int[]{Color.parseColor("#ff9900"), Color.parseColor("#ff9900")};
} else if (colors.length == 1) {//单色处理
int[] newColor = new int[]{colors[0], colors[0]};
colors = newColor;
}
int width = originalBitmap.getWidth();
int height = originalBitmap.getHeight();
Canvas canvas = new Canvas(originalBitmap);//Canvas中Bitmap是用来保存像素,相当于画纸
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0, 0, width, height, colors, null, Shader.TileMode.CLAMP);//shader:着色器,线性着色器设置渐变从左上坐标到右下坐标
paint.setShader(shader);//设置着色器
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//设置图像混合模式
canvas.drawRect(0, 0, width, height, paint);
return originalBitmap;
}
}
效果如图:
本文地址:https://blog.csdn.net/clg19780720/article/details/107159591
推荐阅读
-
Android DSelectorBryant 单选滚动选择器
-
Android修改DatePicker字体颜色及分割线颜色详细介绍
-
基于android背景选择器selector的用法汇总
-
Android更改EditText下划线的颜色样式和动态获取输入的字数的代码教程
-
利用Android模仿微信摄像圆环进度效果实例
-
Android 中TeaPickerView数据级联选择器功能的实例代码
-
Android编程实现自定义渐变颜色效果详解
-
Android Selector 按下修改背景和文本颜色的实现代码
-
Android样式和主题之选择器的实例讲解
-
Android开发之滑动数值选择器NumberPicker用法示例