Android自定义View之七色环颜色采集器: 续我未完的大学梦 !

Android自定义View之七色环颜色采集器:续我未完的大学梦!!


一、前言。

在大学期间,看到机智云开源的这个rgb灯,蛮好奇的,这么漂亮的颜色采集,并且可以同步到设备rbg灯颜色,甚是不解!这个谜团一直在心中困惑。

越是好奇,越是扬起袖子就是干!于是乎,自己结合自己的开发经验和网上开源的代码,进一步的剖析原理,把分析过程一一展现给大家。

标题为啥是 续我未完的大学梦 呢?因为大学对这个界面“一见钟情”,相信这个也是大家所好奇的。为什么手机的颜色可以同步设备rbg灯的颜色,那本文主要讲怎么绘制这么一个界面,具体的同步颜色到设备的原理,我不一一分析了,当然了,会透漏一点点。


这里写图片描述


下面的是我练手项目一个工程的一个设备控制界面,到时候会开源出来滴:

这里写图片描述


二、绘图步骤:


绘图原理:


这里写图片描述


绘图步骤:


这里写图片描述


第一步:先画圆环和内部圆。

  • 具体的自定义画圆的步骤大家都熟悉。画笔、测量。

    • 画笔初始化不必多说,强调下渐变色环画笔的stytle属性;还有渐变色环通过SweepGradient类实现。

    Paint.Style.STROKE : 只绘制图形轮廓(描边), 通常的圆环设置这个属性
    Paint.Style.FILL : 只绘制图形内容 。
    Paint.Style.FILL_AND_STROKE : 既绘制轮廓也绘制内容。

        //circleX 渲染中心点x坐标,circleY渲染中心y点坐标;mCircleColors为渐变颜色内容
        Shader s = new SweepGradient(circleX, circleY, mCircleColors, null);
        paintCircleRing.setShader(s);
  • 测量:取整个父布局的view的宽和高,对比取最小一个,保证了半径可以被整个view包裹。

    //圆环的画笔
    private Paint paintCircleRing;

    //最里面的圆的画笔,默认是绿色
    private Paint paintInnerColor;

    //渐变色环参数:红、紫、蓝、绿、黄、橙、红
    private final int[] mCircleColors = new int[]{0xFFFF0000, 0xFFFF00FF,
            0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000};


     //初始化画笔,构造方法调用。
     private void init() {
        // 渐变色环参数
        paintCircleRing = new Paint(Paint.ANTI_ALIAS_FLAG);
        paintCircleRing.setAntiAlias(true);
        paintCircleRing.setStyle(Paint.Style.STROKE);
        paintCircleRing.setStrokeWidth(30);

        //内圆参数
        paintInnerColor = new Paint();
        paintInnerColor.setColor(Color.GREEN);
        paintInnerColor.setAntiAlias(true);
        paintInnerColor.setStrokeWidth(5);

    }

效果:


这里写图片描述


三、画圆形图片选择器。

  • 1、 已知圆环的半径outerRadius 和原点的坐标 (circleX , circleY) ,通过博文的第一个原理图可得选择器坐标:
         //选择器x坐标
        markPointX = (float) (circleX + outerRadius * Math.sin(angle * Math.PI / 180));
         //选择器y坐标
        markPointY = (float) (circleY - outerRadius  * Math.cos(angle * Math.PI / 180));

  • 2、 画圆点选择器(下图的左边):

这里写图片描述

  • frameRadius 半径就是外圆半径减去OC的长度除于2;

 canvas.drawCircle(markPointX, markPointY, frameRadius, paintSelecter);

四、颜色求角度。

  • 毋庸置疑,当先从颜色十六进制拿出R、G、B颜色和色环的颜色对比得到结论。

  private float fromColor2Degree(int color) {

        float degree = 0;
        int diff = 360 / (mCircleColors.length - 1);

        int r = Color.red(color);
        int g = Color.green(color);
        int b = Color.blue(color);

        int[] mColor = {b, g, r};

        // 把最大的,置0xFF,最小的,置0
        int min = findMin(b, g, r);
        int max = findMax(b, g, r);

        int temp = (0xff << (max * 8)) + (0xff << (8 * 3));

        if (max == min) {//证明RGB相等;
            return 90;// 九十度
        }

        int mid = 3 - max - min;
        int start = 0;
        int end = 0;
        for (int i = 0; i < mCircleColors.length - 2; i++) {
            if (mCircleColors[i] - temp == 0)
                start = i;
            if (mCircleColors[i] - temp == (0xff << (mid * 8)))
                end = i;
        }
        float percent = (float) mColor[mid] / (float) 0xff;
        int degreeDiff = (int) (percent * diff);

        if (start < end) {
            degree = start * diff;
            degree += degreeDiff;
        } else {
            degree = start * diff;
            degree -= degreeDiff;
        }

        degree += 90;

        if (degree > 360)
            degree -= 360;

        return degree;
    }

五、角度求颜色。

   //获取圆环上颜色
    private int interpCircleColor(int colors[], float degree) {
        degree -= 90;

        if (degree < 0)
            degree += 360;

        float p = degree * (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);
    }

六、点击事件。

  • 这部分不难理解,只要把触摸点的坐标和小圆点的坐标做对比处理,只要是在其周围60dp周围,就认为是触摸到了小圆点选择器。

 private boolean isMarkPointRange(float x, float y) {
        float range = dp2px(getContext(), 60);
        return x > (markPointX - range) && x < (markPointX + range) && y > (markPointY - range) && y < (markPointY + range);
    }

七、view的点击事件传递。

  • 当用户按下手指的位置在圆点周围时候就拦截,否则不拖动小圆点。
    -
    • getParent().requestDisallowInterceptTouchEvent(true);

@Override
    public boolean onTouchEvent(MotionEvent event) {

        float markRange = dp2px(getContext(), 60);
        float x = event.getX();
        float y = event.getY();
        boolean up = false;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
             //当用户按下手指的位置在圆点周围时候就拦截
                if (x < markPointX + markRange && x > markPointX - markRange
                        && y > markPointY - markRange && y < markPointY + markRange) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                moved(x, y, up);
                break;
            case MotionEvent.ACTION_MOVE:
                moved(x, y, up);
                break;
            case MotionEvent.ACTION_UP:
                up = true;
                moved(x, y, up);
                break;
           //当用户取消的手势,就不滑动了
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                up = true;
                moved(x, y, up);
                break;
        }
        return true;
    }

八、小圆点的拖动。

 private void moved(float x, float y, boolean up) {

        //判断触摸点是否在圆环内
        if (!isMarkPointRange(x, y)) {
            return;
        }

        float distance = (float) Math.sqrt(Math.pow((x - circleX), 2)
                + Math.pow((y - circleY), 2));

        if (distance < outerRadius + 100 && distance > innerRadius - 100 && !up) {

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

            //改变内部圆的颜色
            int CircleColor = interpCircleColor(mCircleColors, degrees);
            paintInnerColor.setColor(CircleColor);

            //角度四舍五入
            this.angle = Math.round(degrees);
            invalidate();
        } else {
            if (mSeekBarColorPickerChangeListener != null) {
                mSeekBarColorPickerChangeListener.onProgressChange(this, paintInnerColor.getColor());
            }
            invalidate();
        }

    }

详情请移步:http://www.demodashi.com/demo/11892.html


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半颗心脏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值