欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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;
    }
}

效果如图:

Android圆环颜色选择器
Android圆环颜色选择器
Android圆环颜色选择器

本文地址:https://blog.csdn.net/clg19780720/article/details/107159591