一个非常不错的颜色圆环选择器视图,由于项目需要自己写了一个圆环颜色选择器,部分代码来源与网络,如有相同敬请谅解。废话不多说,直接上源代码:
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; } }
效果如图:
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/addevelopment/898126.html