Android 自定义颜色选择器 ----- HSL 颜色选择器

话不多说先贴效果图:


颜色选择器效果图

关于HSL颜色

HSL[色彩模式]是工业界的一种颜色标准,是通过对色相(H)、饱和度(S)、亮度(L)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,HSL即是代表色相,饱和度,亮度三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是迄今运用最广的颜色系统之一。

也就是说,HSL颜色值由三个浮点数字组成:
色相(H):0----360 浮点数
饱和度(S):0----1 浮点数
亮度(L):0----1 浮点数

色相环颜色标准值(这里使用6色相环):

 private final int[] mColors = new int[] {//渐变色数组
            0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
            0xFFFFFF00, 0xFFFF0000
    };

获取亮度标准值:

private int[] getLightness(float[] hsl_color){
        int[] colors =new int[10];
        float[] floatArray = new float[3];
        for (int i = 0 ;i <3 ;i++){
            floatArray[i] = hsl_color[i];
        }
        for(int i=0;i < 10;i++){
            floatArray[2] =((float) i)/9;
            colors[i] = ColorUtils.HSLToColor(floatArray);
        }
        return colors;
    }

获取饱和度标准值:

private int[] getSaturation(float[] hsl_color){
        int[] colors =new int[10];
        float[] floatArray = new float[3];
        for (int i = 0 ;i <3 ;i++){
            floatArray[i] = hsl_color[i];
        }
        for(int i=0;i < 10;i++){
            floatArray[1] =((float) i)/9;
            colors[i] = ColorUtils.HSLToColor(floatArray);
        }
        return colors;
    }

获取关键点位置:

 private float[] getPositionArray(float offset){
        float[] colorPosition = new float[10];
        for (int i=0;i < 10;i++) {
            colorPosition[i] = i * (((float)144) / 9) / 360f + offset;
        }
        return colorPosition;
    }

极坐标和普通坐标的转换:

private float[] RectToPolar(float x,float y){
        float polar[] = new float[2];
        if(x == 0){
            if(y>0){
                polar[0] = (float) (Math.PI/2);
            }else {
                polar[0] = (float) (3 * Math.PI/2);
            }
            polar[1] = Math.abs(y);
        }else{
            if(x<0){
                polar[0] = (float) Math.atan(y/x) +(float)Math.PI;
            }else {
                if(y>=0){
                    polar[0] = (float) Math.atan(y/x);
                }else {
                    polar[0] = (float) Math.atan(y/x) +2 * (float) Math.PI;
                }
            }
            polar[1] = (float) Math.sqrt(x*x +y*y);
        }
        return polar;
    }

    private float[] PolarToRect(float[] polar){
        float[] rect = new float[2];
        rect[0] = (float) (polar[1] * Math.cos(polar[0]));
        rect[1] = (float) (polar[1] * Math.sin(polar[0]));
        return rect;
    }

整体代码如下:

public class ColorPicker extends View {

    private  GestureDetector gestureDetector;
    private int radius,height,width;
    private Paint paintLine;

    private float scale = (float) (144 * Math.PI/180);

    private Paint mCenterPaint;

    private int mInitialColor = Color.BLACK;//初始颜色

    private final int[] mColors = new int[] {//渐变色数组
            0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
            0xFFFFFF00, 0xFFFF0000
    };

    private int paintColor;

    private float[] hsl_color = new float[3];

    private Paint mPaint,saturationPaint,lightnessPaint,indicatorPaint;

    public ColorPicker(Context context) {
        super(context);
    }

    public ColorPicker(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ColorPicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init_paint();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取宽的测量模式
        int heightSize =  MeasureSpec.getSize(heightMeasureSpec);//测量值
        height= resolveSize(heightSize, heightMeasureSpec);
        int widthSize =  MeasureSpec.getSize(widthMeasureSpec);//测量值
        width= resolveSize(widthSize, widthMeasureSpec);
        if(height <200) height = 200;
        if(width < 200) width = 200;
        radius = (width < height? width/2:height/2) - 20;
        setMeasuredDimension(width,height);
    }

    private int[] getSaturation(float[] hsl_color){
        int[] colors =new int[10];
        float[] floatArray = new float[3];
        for (int i = 0 ;i <3 ;i++){
            floatArray[i] = hsl_color[i];
        }
        for(int i=0;i < 10;i++){
            floatArray[1] =((float) i)/9;
            colors[i] = ColorUtils.HSLToColor(floatArray);
        }
        return colors;
    }

    private float[] getPositionArray(float offset){
        float[] colorPosition = new float[10];
        for (int i=0;i < 10;i++) {
            colorPosition[i] = i * (((float)144) / 9) / 360f + offset;
        }
        return colorPosition;
    }

    private int[] getLightness(float[] hsl_color){
        int[] colors =new int[10];
        float[] floatArray = new float[3];
        for (int i = 0 ;i <3 ;i++){
            floatArray[i] = hsl_color[i];
        }
        for(int i=0;i < 10;i++){
            floatArray[2] =((float) i)/9;
            colors[i] = ColorUtils.HSLToColor(floatArray);
        }
        return colors;
    }

    public void setPaintColor(float[] hsl_color){
        this.hsl_color = hsl_color;
        this.mInitialColor = ColorUtils.HSLToColor(hsl_color);
        indicatorPaint.setColor(mInitialColor);
        mCenterPaint.setColor(mInitialColor);

        Shader saturation = new SweepGradient(0, 0, getSaturation(hsl_color), getPositionArray(0.55f));
        saturationPaint.setShader(saturation);


        Shader lightness = new SweepGradient(0, 0, getLightness(hsl_color), getPositionArray(0.05f));
        lightnessPaint.setShader(lightness);
        invalidate();
    }


    private void init_paint(){
        ColorUtils.colorToHSL(Color.BLACK,hsl_color);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Shader s = new SweepGradient(0, 0, mColors, null);
        mPaint.setShader(s);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(20);

        indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        indicatorPaint.setStrokeWidth(2);

        //初始化中心园画笔
        mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCenterPaint.setStrokeWidth(2);

        saturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        saturationPaint.setStrokeCap(Paint.Cap.ROUND);
        saturationPaint.setStyle(Paint.Style.STROKE);
        saturationPaint.setStrokeWidth(20);

        lightnessPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        lightnessPaint.setStrokeCap(Paint.Cap.ROUND);
        lightnessPaint.setStyle(Paint.Style.STROKE);
        lightnessPaint.setStrokeWidth(20);
        setPaintColor(hsl_color);
    }

    private float[] RectToPolar(float x,float y){
        float polar[] = new float[2];
        if(x == 0){
            if(y>0){
                polar[0] = (float) (Math.PI/2);
            }else {
                polar[0] = (float) (3 * Math.PI/2);
            }
            polar[1] = Math.abs(y);
        }else{
            if(x<0){
                polar[0] = (float) Math.atan(y/x) +(float)Math.PI;
            }else {
                if(y>=0){
                    polar[0] = (float) Math.atan(y/x);
                }else {
                    polar[0] = (float) Math.atan(y/x) +2 * (float) Math.PI;
                }
            }
            polar[1] = (float) Math.sqrt(x*x +y*y);
        }
        return polar;
    }

    private float[] PolarToRect(float[] polar){
        float[] rect = new float[2];
        rect[0] = (float) (polar[1] * Math.cos(polar[0]));
        rect[1] = (float) (polar[1] * Math.sin(polar[0]));
        return rect;
    }

    public int getColor(){
        return mInitialColor;
    }

    public float[] getHslColor(){
        return hsl_color;
    }

    private int mode = -1;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & event.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:           // 第一个手指按下事件
                float[] r = RectToPolar(event.getX() - width/2,event.getY() - height/2);
                if(r[1]<(radius+radius/6) && r[1] >(radius - radius/6) ){
                    mode = 1;
                }else if(r[1]<(radius*2/3+radius/6) && r[1] >(radius*2/3 - radius/6)){
                    if(r[0] < Math.PI/2 || r[0]>3 * Math.PI/2){
                        mode = 3;
                    }else {
                        mode = 2;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                mode = -1;

                break;
            case MotionEvent.ACTION_MOVE:
                float[] p = RectToPolar(event.getX() - width/2,event.getY() - height/2);
                switch (mode){
                    case 1:
                        hsl_color[0] =360 - (p[0] * 360) /(float) (Math.PI *2);
                        setPaintColor(hsl_color);
                        break;
                    case 2:
                        hsl_color[1] = (p[0] + (float) Math.PI/2 - 198 * (float)Math.PI/180)/scale;
                        if(hsl_color[1] > 1){
                            hsl_color[1] = 1;
                        }
                        if(hsl_color[1] < 0){
                            hsl_color[1] = 0;
                        }
                        setPaintColor(hsl_color);
                        break;
                    case 3:
                        if(p[0] > Math.PI){
                            hsl_color[2] =  (p[0] + (float) Math.PI/2 - 2*(float)Math.PI - 18 * (float)Math.PI/180)/scale;
                        }else {
                            hsl_color[2] =  (p[0] + (float) Math.PI/2 - 18 * (float)Math.PI/180)/scale;
                        }
                        if(hsl_color[2] > 1){
                            hsl_color[2] = 1;
                        }
                        if(hsl_color[2] < 0){
                            hsl_color[2] = 0;
                        }
                        setPaintColor(hsl_color);
                        break;
                }
                invalidate();
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(width/2,height/2);
        canvas.drawCircle(0, 0, radius , mPaint);
        canvas.drawCircle(0, 0, radius/3 ,mCenterPaint );
        float[] porlar = new float[2];
        porlar[0] = -2 * (float) Math.PI *(hsl_color[0]/(float) 360);
        porlar[1] = radius;
        canvas.drawCircle(PolarToRect(porlar)[0],PolarToRect(porlar)[1],20,mCenterPaint);
        int sl_radius = radius * 2/3;
        RectF oval = new RectF(-sl_radius ,-sl_radius, sl_radius, sl_radius);
        int[] colorArray = new int[]{Color.RED, Color.YELLOW, Color.BLUE, Color.GREEN};
        canvas.rotate(-90); //h
        canvas.drawArc(oval,18 ,144,false,lightnessPaint); //l
        canvas.drawArc(oval,198 ,144,false,saturationPaint);//v
        porlar[1] = sl_radius;
        porlar[0] = 2 * (float) Math.PI *((144 * hsl_color[2] + 18 )/(float) 360);
        canvas.drawCircle(PolarToRect(porlar)[0],PolarToRect(porlar)[1],20,mCenterPaint);
        porlar[0] = 2 * (float) Math.PI *((144 * hsl_color[1] + 198 )/(float) 360);
        canvas.drawCircle(PolarToRect(porlar)[0],PolarToRect(porlar)[1],20,mCenterPaint);
    }
}

完工,颜色选择器完成。然后直接调用就好了。

<com.example.drawboard.view.ColorPicker
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

看了文章给个赞呗

--------------------------------传说中的底线在这里---------------------------------

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容