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

Posted CrazyMo_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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进阶之绘制-自定义View完全掌握

Android进阶之绘制-自定义View完全掌握

Android进阶之绘制-自定义View完全掌握

Android进阶之绘制-自定义View完全掌握

Android安卓进阶技巧之自定义View系列(绘制流程)

Android自定义View学习三---图形绘制