首页 > 代码库 > Android进阶——自定义View之自己绘制彩虹圆环调色板

Android进阶——自定义View之自己绘制彩虹圆环调色板

引言

前面几篇文章都是关于通过继承系统View和组合现有View来实现自定义View的,刚好由于项目需要实现一个滑动切换LED彩灯颜色的功能,所以需要一个类似调色板的功能,随着手在调色板有效区域滑动,LED彩灯随即显示相应的颜色,也可以通过左右的按钮,按顺序切换显示一组颜色,同时都随着亮度的改变LED彩灯的亮度随即变化,这篇基本上把继承View重绘实现自定义控件的大部分知识总结了下(当然还有蛮多没有涉及到,比如说自适应布局等),源码在Github上

一、继承View绘制自定义控件的通用步骤

  • 自定义属性和继承View重写onDraw方法

  • 实现构造方法 ,其中public RainbowPalette(Context context, AttributeSet attrs) 必须实现,否则无法通过xml引用,public RainbowPalette(Context context) ,public RainbowPalette(Context context, AttributeSet attrs, int defStyleAttr)可选,通常在构造方法中完成属性和其他成员变量的初始化

  • 重写onMeasure方法,否则在xml中有些设置布局参数无效

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(width, height);//重新设置View的位置,若不重写的话,则不会布局,即使设置centerInParent为true也无效
        //setMeasuredDimension(width,height);
    }
  • 手动调用invalidate或者postInvalidateon方法完成界面刷新

  • 重写onTouchEvent方法实现基本的交互

  • 定义回调接口供外部调用

二、彩虹圆环调色板设计思想

技术分享

1、UI构成

首先从整个形状来看是个圆环,系统自有的控件明显没具有这个功能,只能是继承View重写OnDraw来完成绘制工作。前面Android入门——利用Canvas完成绘制点、圆、直线、路径、椭圆、多边形等2D图形可以知道通过Paint可以在Canvas绘制任何图形,包括圆环,于是整体的结构就出来了,中心实体小圆作为指示当前颜色的标记,外圈渐变色圆环作为调色板的取色区域(可以通过给Paint传入Shader shader = new SweepGradient(0, 0, gradientColors, null)来绘制渐变色),最外圈的光环可以绘制多个圆环,而作为指示器标记的小圆点(也可以传入图片资源)也是一个圆形,如此一来UI方面的结构基本明了。

2、交互设计

一般来说自定义View的人机交互都是通过回调的方式的来实现的。

  • 滑动选择颜色:自定义控件的滑动自然是重写onTouchEvent,然后调用invalidate手动触发View重绘(即重新调用onDraw)

  • 颜色指示器的显示的位置:手动触发invalidate重新调用onDraw绘制

  • 中心圆形自动同步选中的颜色:手动触发invalidate重新调用onDraw绘制

  • 仅在圆环处滑动选择颜色:如果面积小于外圆大于内圆的就认为是有效滑动

    /**
     * 是否是有效Touch即是否是按在圆环之上的
     * @return
     */
    private boolean isEfectiveTouch(float x, float y, float outRadius, float inRadius){
        double outCircle = Math.PI * outRadius * outRadius;
        double inCircle = Math.PI * inRadius * inRadius;
        double fingerCircle = Math.PI * (x * x + y * y);
        if(fingerCircle < outCircle && fingerCircle > inCircle) {
            return true;
        }else {
            return false;
        }
    }

三、实现彩虹圆环调色板

1、自定义属性

attr.xml

<declare-styleable name="rainbow_palette">
        <attr name="palette_color" format="color"/>
        <!-- 可滑动小球的颜色 -->
        <attr name="indicator_color" format="color" />
        <!--中间指示当前选中颜色值的圆-->
        <attr name="center_circle_defcolor" format="color"/>
        <!-- 外圈圆环的半径 -->
        <attr name="out_circle_radius" format="dimension" />
        <!-- 调色环的外圈圆环的半径 -->
        <attr name="palette_radius" format="dimension" />
        <!-- 中心圆环的半径 -->
        <attr name="center_radius" format="dimension" />
        <!-- 调色环的宽度 -->
        <attr name="palette_width" format="dimension" />
        <!-- 可滑动小球的半径 -->
        <attr name="indicator_radius" format="dimension" />
        <!--用其他图片来代替绘制的指示器的小圆-->
        <attr name="ic_indicator" format="reference"/>
    </declare-styleable>

2、重写View

import com.xiaoi.app.zkSmartHome.R;

/**
 * auther: Crazy.Mo
 * Date: 2016/12/13
 * Time:10:27
 * Des:自定义的调色板,可以绘制圆形指示器,也可以自定义图标指示器,但是指示器会超出边界
 */
public class RainbowPalette extends View {
    private Context context;
    private Paint borderPaint;//色环外圈的彩虹圆环
    private Paint palettePaint;//渐变色环的画笔
    private Paint centerPaint;//中间圆画笔,用于显示当前选中的颜色
    private Paint indictorPaint; // 可移动小球画笔
    private int indictorColor;
    private int[] gradientColors;//渐变色环颜色
    private int centerCircleColor;
    private int width;//当前调色板的宽度
    private int height;//当前调色板的高度
    private float paletteRadius;//色环半径,整个环形外径,直接决定这个调色板的整体的大小,画渐变环可以看成画一个完整的圆形再挖掉一个小圆
    private float centerRadius;//中心圆半径
    private float paletteWidth;//色环的宽度
    private float indictorRadius;//小球的半径
    private Point indictorPosition;// 小球当前位置
    private Point centerPosition;//圆心的位置,色环圆心的位置
    private Bitmap indicatorBitmap; // 指示器小球的图标
    private int indictorResId;//指示器图标的id
    private RainbowPalette.OnColorChangedListen listen;
    private static boolean isShowIndictor=true;

    private final static int BORDER_WIDTH=2;
    private final static int PALETTE_WIDTH=100;
    private final static int CENTER_CIRCLE_WIDTH=5;
    private final static int INDICTOR_WIDTH=5;
    private final static int DEF_INDICTOR_COLOR=0xFFc9f5f1;//设置指示小圆形的颜色
    private final static int DEF_CIRCLE_COLOR=0xFF0511FB;//设置中间圆的默认颜色

    public RainbowPalette(Context context) {
        super(context);
    }
    public RainbowPalette(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(attrs);
    }
    public RainbowPalette(Context context, AttributeSet attrs, int defStyleAttr){
        super(context, attrs, defStyleAttr);
        this.context=context;
        init(attrs);
    }

    private void init(AttributeSet attrs){
        setPaletteSize();
        initAttrColor(attrs);
        initPaint();
        initPosition();
        initRadiusWidth(attrs);
    }

    /**
     * 用于设置中间圆的颜色
     * @param color
     */
    public void setCenterPaint(int color){
        centerPaint.setColor(color);
    }

    /**
     * 设置调色板的尺寸
     */
    private void setPaletteSize(){
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//获取WM对象
        int height = (int) (manager.getDefaultDisplay().getHeight() * 0.5f);//获取屏幕的高度*0.5
        int width = (int) (manager.getDefaultDisplay().getWidth() * 0.7f);//获取屏幕宽度的0.7
        this.height = height - 36;
        this.width = width;
        setMinimumHeight(height - 36);
        setMinimumWidth(width);
    }

    /**
     * 设置颜色指示器的位置
     * @param point
     */
    public void setIndictorPosition(Point point){
        if(point!=null) {
            this.indictorPosition.x = point.x;
            this.indictorPosition.y = point.y;
        }
    }

    /**
     * 设置是否显示颜色指示器
     * @param isShow
     */
    public static void setIndictorShow(boolean isShow){
        RainbowPalette.isShowIndictor=isShow;
    }

    /**
     * 设置指示器小球Color的默认值
     * @param color
     */
    public void setBallColor(int color){
        this.indictorColor=color;
    }

    /**
     * 初始化各种Paint对象
     */
    private void initPaint(){
        setGradientColors();
        Shader shader = new SweepGradient(0, 0, gradientColors, null);//SweepGradient渐变
        //外层彩虹光环
        borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿。给Paint加上抗锯齿标志
        borderPaint.setAntiAlias(true);
        borderPaint.setShader(shader);//传入着色器
        borderPaint.setStyle(Paint.Style.STROKE);//设置仅描边
        borderPaint.setStrokeWidth(BORDER_WIDTH);//设置描边的宽度,直接对应

        //初始化色环的Paint对象
        palettePaint = new Paint(Paint.ANTI_ALIAS_FLAG);//在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿。给Paint加上抗锯齿标志
        palettePaint.setAntiAlias(true);
        palettePaint.setShader(shader);//传入着色器
        palettePaint.setStyle(Paint.Style.STROKE);//设置仅描边
        palettePaint.setStrokeWidth(PALETTE_WIDTH);//设置描边的宽度,直接对应
        //初始化中心圆的Paint对象
        centerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        centerPaint.setAntiAlias(true);
        centerPaint.setColor(centerCircleColor);
        centerPaint.setStrokeWidth(CENTER_CIRCLE_WIDTH);
        //初始化小球对象
        indictorPosition=new Point();
        indictorPaint= new Paint(Paint.ANTI_ALIAS_FLAG);
        indictorPaint.setAntiAlias(true);
        indictorPaint.setColor(indictorColor);
        indictorPaint.setStrokeWidth(INDICTOR_WIDTH);
    }

    private void initAttrColor(AttributeSet attrs){
        TypedArray types = context.obtainStyledAttributes(attrs,
                R.styleable.rainbow_palette);
        try {
            centerCircleColor = types.getColor( R.styleable.rainbow_palette_center_circle_defcolor,DEF_CIRCLE_COLOR );
            indictorColor = types.getColor( R.styleable.rainbow_palette_indicator_color,DEF_INDICTOR_COLOR );
        } finally {
            types.recycle(); // TypeArray用完需要recycle
        }
    }

    /**
     * 设置色环和中心圆、圆形指示小球的半径,宽度
     */
    private void initRadiusWidth(AttributeSet attrs){
        TypedArray types = context.obtainStyledAttributes(attrs,
                R.styleable.rainbow_palette);
        try {

            paletteWidth = types.getDimensionPixelOffset( R.styleable.rainbow_palette_palette_width, PALETTE_WIDTH);
            paletteRadius=types.getDimensionPixelOffset(R.styleable.rainbow_palette_palette_radius,(int)(width / 2 - palettePaint.getStrokeWidth()*1.2f));
            centerRadius=types.getDimensionPixelOffset(R.styleable.rainbow_palette_palette_radius,(int)((paletteRadius - palettePaint.getStrokeWidth() / 2 ) * 0.5f));
            indictorResId=types.getResourceId(R.styleable.rainbow_palette_ic_indicator,0);
            if(indictorResId==0) {
                //未指定指示器的图标采用默认的绘制一个小圆形
                indictorRadius = (float) (centerRadius * 0.5);
            }else {
                initIndictorImg();//使用设置的指示器目标
            }
        } finally {
            types.recycle(); // TypeArray用完需要recycle
        }
    }

    /**
     * 初始化颜色指示器,设置指定图片
     */
    private void initIndictorImg(){
        // 将背景图片大小设置为属性设置的直径
        indicatorBitmap = BitmapFactory.decodeResource(getResources(), indictorResId );
        //indicatorBitmap = Bitmap.createScaledBitmap(indicatorBitmap, (int)centerRadius,(int)centerRadius, false);
        indicatorBitmap= Bitmap.createScaledBitmap(indicatorBitmap,indicatorBitmap.getWidth(),indicatorBitmap.getHeight(),true);
        indictorRadius=indicatorBitmap.getHeight();
    }

    /**
     * 设置色环的绘制圆心
     */
    private void initPosition(){
        centerPosition=new Point();
        centerPosition.set(width/2,height/2-50);
        indictorPosition.set(0,0);
    }

    /**
     * 设置渐变环的颜色取值
     */
    public void setGradientColors(){
        gradientColors = new int[] {0xFFFF0000, 0xFFFF00FF, 0xFF0000FF,0xFF00FFFF, 0xFF00FF00,0xFFFFFF00, 0xFFFF0000};
    }

    private void drawBorder(Canvas canvas){
        borderPaint.setAlpha(220);
        canvas.drawOval(new RectF(-(paletteRadius+55), -(paletteRadius+55), (paletteRadius+55), (paletteRadius+55)), borderPaint);//画次外圈
        borderPaint.setAlpha(100);
        canvas.drawOval(new RectF(-(paletteRadius+60), -(paletteRadius+60), (paletteRadius+60), (paletteRadius+60)), borderPaint);//画外圈
        borderPaint.setAlpha(60);
        canvas.drawOval(new RectF(-(paletteRadius+65), -(paletteRadius+65), (paletteRadius+65), (paletteRadius+65)), borderPaint);//画外圈
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(centerPosition.x,centerPosition.y);//移动中心,要不然会导致画出来之后不能完全显示,此时圆心相当于是由(0,0)变为(width / 2, height / 2 - 50)
        canvas.drawCircle(0,0, centerRadius,  centerPaint);//画中心圆
        canvas.drawOval(new RectF(-paletteRadius, -paletteRadius, paletteRadius, paletteRadius), palettePaint);//画色环
        drawBorder(canvas);
        if(isShowIndictor) {
            if (indictorResId == 0) {
                canvas.drawCircle(indictorPosition.x, indictorPosition.y, (float) (centerRadius * 0.5), indictorPaint);//画颜色指示器小球
            } else {
                canvas.drawBitmap(indicatorBitmap, indictorPosition.x, indictorPosition.y, indictorPaint);//画指示器 指定图片
            }
        }
        Log.e("Position", "indictorPosition: X:"+indictorPosition.x+"Y:"+indictorPosition.y );
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(width, height);//重新设置View的位置,若不重写的话,则不会布局,即使设置centerInParent为true也无效
        //setMeasuredDimension(width,height);
    }

   // 可以实现点击的时候显示对应的指示点,但会超过边界
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX() - width / 2;//event.getX()以父视图的左上角作为原点
        float y = event.getY() - height / 2 + 50;
        boolean isEcfect = isEfectiveTouch(x, y,
                paletteRadius + palettePaint.getStrokeWidth() / 2, paletteRadius - palettePaint.getStrokeWidth() / 2);
        int choosedColor;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if(isEcfect){
                    float angle = (float) Math.atan2(y, x);
                    float unit = (float) (angle / (2 * Math.PI));
                    if (unit < 0) {
                        unit += 1;
                    }
                    choosedColor=getColorByTouchPalette(gradientColors,unit);
                    indictorPosition.set((int) (event.getX()-(width / 2)), (int) (event.getY()-(width / 2)));
                    centerPaint.setColor(choosedColor);
                    if(listen!=null) {
                        listen.onColorChange(choosedColor);
                    }
                }
                else {
                    return false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(isEcfect){
                    float angle = (float) Math.atan2(y, x);
                    float unit = (float) (angle / (2 * Math.PI));
                    if (unit < 0) {
                        unit += 1;
                    }
                    choosedColor=getColorByTouchPalette(gradientColors,unit);
                    indictorPosition.set((int) (event.getX()-(width / 2)), (int) (event.getY()-(width / 2)));
                    centerPaint.setColor(choosedColor);
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if(isEcfect){
                    float angle = (float) Math.atan2(y, x);
                    float unit = (float) (angle / (2 * Math.PI));
                    if (unit < 0) {
                        unit += 1;
                    }
                    choosedColor=getColorByTouchPalette(gradientColors,unit);
                    indictorPosition.set((int) (event.getX()-(width / 2)), (int) (event.getY()-(width / 2)));
                    centerPaint.setColor(choosedColor);
                    if(listen!=null) {
                        listen.onColorChange(choosedColor);
                        listen.onColorChangeUp((int) (event.getX()-(width / 2)), (int) (event.getY()-(width / 2)));
                    }
                }
                return true;
            default:
                break;
        }
        if (isEcfect) {
            invalidate();
        }
        return true;
    }
    /**
     * 获取圆环上颜色
     * @param colors
     * @param unit
     * @return
     */
    private int getColorByTouchPalette(int colors[], float unit) {
        if (unit <= 0) {
            return colors[0];
        }
        if (unit >= 1) {
            return colors[colors.length - 1];
        }
        float p = unit * (colors.length - 1);
        int i = (int)p;
        p -= i;

        // now p is just the fractional part [0...1) and i is the index
        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));
    }

    /**
     * 是否是有效Touch即是否是按在圆环之上的
     * @return
     */
    private boolean isEfectiveTouch(float x, float y, float outRadius, float inRadius){
        double outCircle = Math.PI * outRadius * outRadius;
        double inCircle = Math.PI * inRadius * inRadius;
        double fingerCircle = Math.PI * (x * x + y * y);
        if(fingerCircle < outCircle && fingerCircle > inCircle) {
            return true;
        }else {
            return false;
        }
    }


    /**
     * @describe 勾股定理求触摸点与圆心之间直线与水平方向的夹角角度
     * @param a 触摸点
     * @param b 圆心
     * @return
     */
    public float getRadian(Point a, Point b) {
        float lenA = Math.abs(b.x - a.x);
        float lenB = Math.abs(b.y - a.y);
        float lenC = (float) Math.sqrt(lenA * lenA + lenB * lenB);
        float ang = (float) Math.acos(lenA / lenC);
        ang = ang * (b.y < a.y ? -1 : 1);
        return ang;
    }

    /**
     * 设置小球的绘制位置,只能绘制在色环内
     * @return
     */
    private Point setIndictorPositionBorder(int x, int y){
        Point touchPosition=new Point(x,y);
        Point centerCircle=new Point(0,0);
        float radian=getRadian(touchPosition,centerCircle);
        float distance=getTwoPointDistance(centerCircle,touchPosition);//touch点和圆心之间的距离
        float touchToBallDistance;//touch点和内切时小球圆心所在的位置之间的距离,如果不超出色环之外,这两点位置重合,如果超出了则自动移到内切位置处
        if(distance+indictorRadius>(int)paletteRadius){
            touchToBallDistance= Math.abs(distance-paletteRadius+indictorRadius);//touch点和内切(与外环)时小球圆心所在的位置之间的距离
            if(Math.abs(Math.cos(radian))==1){//如果夹角为0或者180°
                if(x<0){
                    indictorPosition.set(-(int)(paletteRadius-20),0);
                }else {
                    indictorPosition.set((int)(paletteRadius-20),0);
                }
            }
            indictorPosition.set((int)(x-(Math.cos(radian)*touchToBallDistance)),(int)(y-(Math.sin(radian)*touchToBallDistance)));
        }else if(distance<((int)paletteRadius-160)){
            touchToBallDistance= Math.abs(paletteRadius-160-distance+indictorRadius);//touch点和外切(与内环)时小球圆心所在的位置之间的距离
            indictorPosition.set((int)(x+(Math.cos(radian)*touchToBallDistance)),(int)(y+(Math.sin(radian)*touchToBallDistance)));
        }else {
            indictorPosition.set(x,y);
        }
        return indictorPosition;
    }

    /**
     * 求两点之间的距离
     * @param a
     * @param b
     * @return
     */
    public float getTwoPointDistance(Point a, Point b){
        return (float) Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
    }

    public void setOnChangeListen(OnColorChangedListen listen){
        this.listen=listen;
    }

    public interface OnColorChangedListen{
        void onColorChange(int color);//自定义的颜色切换的时候触发的回调
        void onColorChangeUp(int x,int y);
    }
}

四、应用彩虹圆环调色板

MainActivity.java

public class MainActivity extends AppCompatActivity implements RainbowPalette.OnColorChangedListen ,View.OnClickListener,SeekBar.OnSeekBarChangeListener{

    private RainbowPalette rainbowPalette;
    private TextView txtTitle,txtChoosePre,txtChooseNext;
    private SeekBar seekBar;
    private SparseArray sparseArray;
    private int currentIndex = 6;//当前的颜色的index,默认为蓝色
    private int currentColor;//选中的颜色
    private String currentRGB;
    private int[] ledNormalColor = {0xFFFFFFFF, 0xFFFF0000, 0xFFF3990C, 0xFFEEF60B, 0xFF3C981B, 0xFF3CE2F3, 0xFF0511FB, 0xFFAB56EE};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    private void initViews(){
        rainbowPalette= (RainbowPalette) findViewById(R.id.imv_led_palettle);
        txtTitle= (TextView) findViewById(R.id.id_txt_palette);
        txtChoosePre= (TextView) findViewById(R.id.tv_choose_pre);
        txtChooseNext= (TextView) findViewById(R.id.tv_choose_next);
        seekBar= (SeekBar) findViewById(R.id.id_alpha_seek_bar);
        txtChoosePre.setOnClickListener(this);
        txtChooseNext.setOnClickListener(this);
        rainbowPalette.setOnChangeListen(this);
        seekBar.setOnSeekBarChangeListener(this);
    }
    private void init(){
        initViews();
        initColorPosition();
    }

    /**
     * 手动设置指示小球显示的位置
     */
    public void setIndictorPosition(int index){
        if (sparseArray!=null) {
            rainbowPalette.setIndictorPosition((Point) sparseArray.get(ledNormalColor[index]));
            rainbowPalette.setCenterPaint((ledNormalColor[currentIndex]));
        }
        RainbowPalette.isNeedShowIndictor=false;
        rainbowPalette.invalidate();
    }

    private void onChooseColor(View view){
        switch (view.getId()){
            case R.id.tv_choose_pre:
                setIndictorPosition(choosePreColor());
                break;
            case R.id.tv_choose_next:
                setIndictorPosition(chooseNextColor());
                break;
            default:
                break;
        }
    }

    /**
     * 选择前一种颜色,并返回对应的索引
     *
     * @return
     */
    private int choosePreColor() {
        int size = ledNormalColor.length;
        if (currentIndex == 0) {
            currentIndex = size;
        }
        currentIndex = currentIndex - 1;
        currentColor = ledNormalColor[currentIndex];
        return currentIndex;
    }

    /**
     * 选择后一种颜色,并返回对应的索引
     *
     * @return
     */
    private int chooseNextColor() {
        int size = ledNormalColor.length;
        if (currentIndex == size - 1) {
            currentIndex = -1;
        }
        currentIndex = currentIndex + 1;
        currentColor = ledNormalColor[currentIndex];
        return currentIndex;
    }

    /**
     * 初始化固定颜色对应的坐标值
     */
    private void initColorPosition(){

        Point[] points={new Point(-75,1),new Point(110,-2),new Point(102,-88),new Point(57,-120),
                new Point(-69,-131),new Point(-145,-18),new Point(-64,102),new Point(44,103)} ;
        sparseArray = new SparseArray<String>();
        for(int i=0;i<points.length;i++) {

            sparseArray.append(ledNormalColor[i],points[i] );
        }
    }

    /**
     * 获取argb模式的颜色值并转为字符串
     * @param color
     * @return
     */
    private String parseArgb(int color){
        int a = (color >>> 24);
        int r = (color >>  16) & 0xFF;
        int g = (color >>   8) & 0xFF;
        int b = (color)        & 0xFF;
        return String.valueOf(a)+String.valueOf(r)+String.valueOf(g)+String.valueOf(b);
    }

    private String parseRGB(int color){
        int r = (color >>  16) & 0xFF;
        int g = (color >>   8) & 0xFF;
        int b = (color)        & 0xFF;
        return String.valueOf(r)+String.valueOf(g)+String.valueOf(b);
    }


    @Override
    public void onColorChange(int color) {
        txtTitle.setTextColor(color);
        currentColor=color;
        currentRGB=Integer.toHexString(color);
        Log.e("Color", "onColorChange: "+ Color.red(color)+Color.green(color)+Color.blue(color));
        Log.e("Color", "onColorChange:parseArgb "+parseArgb(color) );
        Log.e("Color", "onColorChange:parseRGB "+parseRGB(color) );
        Log.e("Color", "onColorChange: "+Integer.toHexString(color) );//获取十进制字符串表示argb模式的颜色0xFFF3990C-->fff3990c
    }

    /**
     * 获取最终的颜色值ARGB模式的
     * @param progress
     * @return
     */
    private int getChangedColor(int progress){
        String red,green,blue;
        if(progress==0){
            progress=1;
        }
        if(currentRGB==null){
            currentRGB="FF0511FB";
        }
        red=currentRGB.substring(2,4);
        green=currentRGB.substring(4,6);
        blue=currentRGB.substring(6);
        return Color.argb(progress,Integer.parseInt(red,16),Integer.parseInt(green,16),Integer.parseInt(blue,16));
    }

    @Override
    public void onClick(View v) {
        onChooseColor(v);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

        currentColor = getChangedColor(progress);
        rainbowPalette.setCenterPaint(currentColor);
        Log.e("Color", "onProgressChanged: "+Integer.toHexString(currentColor) );
        rainbowPalette.invalidate();
        txtTitle.setTextColor(currentColor);

        Log.e("Color", "onProgressChanged: rgb"+ Color.red(currentColor)+Color.green(currentColor)+Color.blue(currentColor));
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        return;
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        return;
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:crazymo="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBcg">
    <TextView
        android:id="@+id/id_txt_palette"
        android:textSize="22sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="自定义的调色板CrazyMo"/>

    <RelativeLayout
        android:id="@+id/rl_led_paletle"
        android:layout_below="@id/id_txt_palette"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="86dp"
        android:gravity="center"
        android:layout_alignParentTop="true"
        >

        <TextView
            android:id="@+id/tv_choose_pre"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerInParent="true"
            android:layout_marginLeft="24dp"
            android:layout_marginRight="24dp"
            android:background="@mipmap/bcg_pre_btn"
            android:clickable="true"/>

        <TextView
            android:id="@+id/tv_choose_next"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerInParent="true"
            android:layout_marginRight="24dp"
            android:layout_marginLeft="24dp"
            android:background="@mipmap/bcg_next_btn"
            android:clickable="true"/>

        <com.crazymo.views.widget.RainbowPalette
            crazymo:ic_indicator="@mipmap/src_indicator"
            crazymo:center_circle_defcolor="#0511FB"
            android:id="@+id/imv_led_palettle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@mipmap/img_led_palette" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_led_switch"
        android:layout_width="match_parent"
        android:layout_height="58dp"
        android:layout_marginLeft="24dp"
        android:layout_marginRight="24dp"
        android:orientation="horizontal"
        android:layout_marginTop="30dp"
        android:background="@drawable/shape_list_border"
        android:layout_below="@+id/rl_led_paletle"
        android:layout_centerHorizontal="true">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:paddingLeft="12dp"
            android:text="  彩灯开关" />

        <CheckBox
            android:id="@+id/cb_contrl_led"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="12dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:button="@null"
            android:checked="true"
            android:background="@drawable/selector_color"/>
    </RelativeLayout>
    <LinearLayout
        android:layout_below="@id/rl_led_switch"
        android:layout_width="match_parent"
        android:layout_height="58dp"
        android:layout_marginLeft="24dp"
        android:layout_marginRight="24dp"
        android:orientation="horizontal"
        android:background="@drawable/shape_list_border"
        android:layout_centerHorizontal="true"
        android:gravity="center_horizontal"
        >

        <TextView
            android:id="@+id/tv_set_alpha"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:paddingLeft="12dp"
            android:text="  亮度调节" />

        <SeekBar
            android:id="@+id/id_alpha_seek_bar"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_alignRight="@id/tv_set_alpha"
            android:layout_gravity="center_vertical"
            android:progress="255"
            android:max="255"
            />
    </LinearLayout>

</RelativeLayout>

PS:以上是demo版本,还有一些缺陷,存在的问题有还未把适配不同分辨率的代码更新到Github,小圆形指示器在边界的时候会越界,主要就是这两个问题。还有一个问题困扰了我很久就是如何根据颜色值获得对应的坐标位置以及ARGB转为RGB模式,还请不吝赐教

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Android进阶——自定义View之自己绘制彩虹圆环调色板