环形手势控制条

项目中需要用到环形控制条,查找了资料然后,修改了各位网友的成果,最后达到我们项目中的要求.先看看效果.

主要参考文章:http://blog.csdn.net/alijiahua/article/details/51474580  在此感谢alijiahua的博客









扫描二维码关注公众号,回复: 1638036 查看本文章







核心代码只有两行:canvas.drawArc() canvas.drawText(),其中要用到三角函数,计算起始位置和角度,至今我还是不太 懂,不过我知道写完这篇文章理理就差不多了.

过程是这样的

第一集成View

第二在value下写attr属性文件

第三画底层灰色的圆弧

第四根据手势再绘制顶层的进度

第五画白色的手柄

第六画文字


在value文件夹下属性文件如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorCircleProgressView">
        <!--定义圆环的渐变颜色  这里只用到了color1和color2-->
        <attr name="Color01" format="color"/>
        <attr name="Color02" format="color"/>
        <attr name="Color03" format="color"/>
        <attr name="Color04" format="color"/>
        <attr name="Color05" format="color"/>
        <attr name="Color06" format="color"/>
        <attr name="Color07" format="color"/>
  	<!--定义圆环背景色,默认灰色-->
<attr name="ColorBackGround" format="color"/>
 
 
	<!--定义文字背景色,默认灰色-->
 <attr name="TextColor" format="color"/> <!--定义圆环角度及开始位置的角度, 不建议修改起始角度和viewAngle 圆环到view边框的距离--> <attr name="ViewAngle" format="integer"/> <attr name="StartAngle" format="integer"/> <attr name="ViewPadding" format="integer"/> <!--定义圆环的大小,是否圆角--> <attr name="StrokeWith" format="integer"/> <attr name="IsRound" format="boolean"/> <!--定义温度区间 默认16-30度--> <attr name="StartTemperature" format="integer"/> <attr name="EndTemperature" format="integer"/> <attr name="ProgressTemperature" format="integer"/> <!--定义点的大小和颜色--> <attr name="PointColor" format="color"/> <attr name="PointRadio" format="integer"/> </declare-styleable></resources> 
 
 
 

自定义的View

package com.example.heaterbaby.circleview1;

import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.example.heaterbaby.R;

/**
 * Created by 瑜哥 on 2017/6/17.
 */

public class ColorCircleProgressView  extends View {

    private Paint mPaint,shader_paint;
    private int mStrokeWith;
    private boolean mIsRound;
    private int mColor01= 0xff4455ff,
                mColor02= 0xff987456,
                mColor03= 0xffFF4081,
                mColor04= 0xff123456,
                mColor05= 0xffFF9981,
                mColor06= 0xff99ffff,
                mColor07= 0xff66ff33,
                backGroundColor= Color.GRAY,
                textColor = Color.GRAY;
    private int mViewAangle;
    private int mStartAangle;
    private int mViewPadding;
    private Paint paint_dot;
    private int mPointColor;
    private int mPointRaido;
    private float mView_x0;
    private float mView_y0;
    private int mPointAngle=45;
    private  OnProgressListener mOnProgressListener;
    private ArgbEvaluator argbEvaluator;//颜色渐变插值器
    private int startTemperature;
    private int endTemperature;
    private int progressTemperature;
    private SweepGradient sweepGradient;
    private final String TEMP_TEXT = "℃";

    public void setOnProgressListener(OnProgressListener onProgressListener) {
        mOnProgressListener = onProgressListener;
    }

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

    public ColorCircleProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);

        argbEvaluator = new ArgbEvaluator();//颜色渐变插值器


        /*获取属性集合*/
        TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ColorCircleProgressView, 0, 0);

       /*渐变颜色值*/
        mColor01 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color01, mColor01);
        mColor02 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color02, mColor02);
        mColor03 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color03, mColor03);
        mColor04 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color04, mColor04);
        mColor05 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color05, mColor05);
        mColor06 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color06, mColor06);
        mColor07 = typedArray.getColor(R.styleable.ColorCircleProgressView_Color07, mColor07);
        backGroundColor = typedArray.getColor(R.styleable.ColorCircleProgressView_Color07, backGroundColor);
        textColor = typedArray.getColor(R.styleable.ColorCircleProgressView_TextColor, textColor);

        /*圆环角度,开始的角度,到边框的距离*/
        mViewAangle = typedArray.getInteger(R.styleable.ColorCircleProgressView_ViewAngle, 270);
        mStartAangle = typedArray.getInteger(R.styleable.ColorCircleProgressView_StartAngle, 135);
        mViewPadding = typedArray.getInteger(R.styleable.ColorCircleProgressView_ViewPadding, 50);

        /*圆环的大小及是否圆角*/
        mStrokeWith = typedArray.getInteger(R.styleable.ColorCircleProgressView_StrokeWith, 20);
        mIsRound = typedArray.getBoolean(R.styleable.ColorCircleProgressView_IsRound, true);

        /*手柄Point的颜色和大小*/
        mPointColor = typedArray.getColor(R.styleable.ColorCircleProgressView_PointColor, Color.WHITE);
        mPointRaido = typedArray.getInteger(R.styleable.ColorCircleProgressView_PointRadio, 30);

        /**获取圆环起始温度和当前设置温度*/
        startTemperature = typedArray.getInteger(R.styleable.ColorCircleProgressView_StartTemperature, 16);
        endTemperature = typedArray.getInteger(R.styleable.ColorCircleProgressView_EndTemperature, 30);
        progressTemperature = typedArray.getInteger(R.styleable.ColorCircleProgressView_ProgressTemperature, 26);
        convertTempToDegree(progressTemperature);
        /*设置圆环画笔*/
        SetPaint();

    }


    /**
     * 初始化画笔
     */
    private void SetPaint() {
        paint_dot = new Paint();//手柄画笔
        paint_dot.setColor(mPointColor);
        mPaint = new Paint();//背景灰色画笔
        mPaint.setStyle(Paint.Style.STROKE);  /*画笔为线条线条*/
        mPaint.setStrokeWidth(mStrokeWith);     /*线条的宽*/
        mPaint.setAntiAlias(true);
        shader_paint = new Paint();//进度画笔
        shader_paint.setStyle(Paint.Style.STROKE);  /*画笔为线条线条*/
        shader_paint.setStrokeWidth(mStrokeWith);     /*线条的宽*/
        shader_paint.setAntiAlias(true);               /*抗锯齿*/
        shader_paint.setStrokeCap(Paint.Cap.ROUND);
        if(mIsRound) {mPaint.setStrokeCap(Paint.Cap.ROUND);}  /*是否圆角*/

    }

    @Override
    protected void onDraw(Canvas canvas) {

        /*得到view的宽高*/
        int width = getWidth();
        int height = getHeight();

        /*把宽高赋值给全局变量,得到圆心的坐标*/
        mView_x0=width/2;
        mView_y0=height/2;

        /*设置线性渐变*/
        sweepGradient = new SweepGradient(width/ 2, height/ 2, new int[]{
                mColor01,  mColor02}, null);
        mPaint.setColor(backGroundColor);

        /*温度文本*/
        String temp="";


        /*定义圆环的所占的矩形区域:注意view一定为正方形*/
        RectF rectF = new RectF(0 + mViewPadding, 0 + mViewPadding, width - mViewPadding, width - mViewPadding);

        /*根据矩形区域画扇形:因为sweep的起点在右边中心处,所以先旋转90度画布*/
        canvas.rotate(90,width/2,height/2);
        canvas.drawArc(rectF, mStartAangle - 90, mViewAangle, false, mPaint);//画底层灰色


        /*动态获取圆上起始点的坐标*/
        //圆点坐标:width/2,height/2
        //半径:(width-mViewPadding-mViewPadding)/2
        //角度:a0


        if(mPointAngle<=45){mPointAngle=45;}
        else if(mPointAngle>315&mPointAngle<=360){mPointAngle=315;}

        /*将45-315范围的角度转为0-100*/
        if(mOnProgressListener!=null) {
//            int progress = (int)((mPointAngle - 45) / 2.7);
            int progress = (int)((mPointAngle - 45) / (mViewAangle/(endTemperature-startTemperature)));//(270/(36-16))=mViewAangle/(endTemperature-startTemperature)
//            mOnProgressListener.onScrollingListener(startTemperature+progress);//温度的回调
            mOnProgressListener.onScrollingListener(mPointAngle);
            temp=String.valueOf(startTemperature + progress);
        }
        //颜色差值器
        Integer color = (Integer) argbEvaluator.evaluate((mPointAngle - 45) / 270f, mColor01, mColor02);


        float x0=width/2;
        float y0=height/2;
        float R = (float) ((width - mViewPadding - mViewPadding) / 2);
        float Point_x= (float) (x0+R*Math.cos(mPointAngle*3.14/180));
        float Point_y= (float) (y0+R*Math.sin(mPointAngle * 3.14 / 180));

        shader_paint.setShader(sweepGradient);
        if (mPointAngle !=45) {//如果为45度,也就是起始位置时会画整个弧形
            canvas.drawArc(rectF, mStartAangle - 90, mPointAngle-45, false, shader_paint);//画划过的弧度
        }
        paint_dot.setStrokeWidth(mStrokeWith/4);
        canvas.drawCircle(Point_x,Point_y,mPointRaido, paint_dot);//画点 手柄
        Paint paint_nano = new Paint();
        paint_nano.setStrokeWidth(mStrokeWith/8);
        paint_nano.setColor(color);
        canvas.drawCircle(Point_x,Point_y,mPointRaido/2, paint_nano);//画点 手柄内原点颜色
        canvas.save();//保存以上内容,否则写文字会旋转90度
        canvas.rotate(-90,width/2,height/2);//旋转画布-90度
        paint_nano.setColor(textColor);
        paint_nano.setTextSize(width*0.2f);
        Rect rect = new Rect();
        paint_nano.getTextBounds(temp,0,temp.length(),rect);//测量温度文本大小


        canvas.drawText(temp,width/2-rect.width()/2,height/2+rect.height()/2,paint_nano);//绘制温度
        paint_nano.setTextSize(width*0.1f);//使画笔变小
        canvas.drawText(TEMP_TEXT,width/2+rect.width()/2,height/2-rect.height()/2,paint_nano);//绘制℃


        //计算底部起始温度,结束温度的位置 完全是实验出来的数据
        float pointX_startT= (float) (x0+R*Math.cos(45+90*3.14/180));
        float pointY_startT= (float) (y0+R*Math.sin(45 +90* 3.14 / 180));
        float pointX_endT= (float) (x0+R*Math.cos(45*3.14/180));
        float pointY_endT= (float) (y0+R*Math.sin(45 * 3.14 / 180));
        paint_nano.setTextSize(width*0.08f);
        Rect rect1 = new Rect();
        paint_nano.getTextBounds(TEMP_TEXT,0,TEMP_TEXT.length(),rect1);//测量起始温度文本大小
        canvas.drawText(startTemperature+"",pointX_startT+rect1.width()/2, (float) (pointY_startT+rect1.height()*3.5),paint_nano);//绘制起始温度
        canvas.drawText(endTemperature+"",pointX_endT-rect1.width(),pointY_endT+rect1.height()*2,paint_nano);//绘制结束温度


        //保存以上内容
        canvas.restore();


    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        /*获取点击位置的坐标*/
        float Action_x = event.getX();
        float Action_y = event.getY();

        /*根据坐标转换成对应的角度*/
        float get_x0 = Action_x - mView_x0;
        float get_y0 = Action_y - mView_y0;
        /*01:左下角区域*/
        if(get_x0<=0&get_y0>=0){
            float tan_x = get_x0 * (-1);
            float tan_y = get_y0;
            double atan = Math.atan(tan_x / tan_y);
            mPointAngle= (int) Math.toDegrees(atan);
        }

        /*02:左上角区域*/
        if(get_x0<=0&get_y0<=0){
            float tan_x = get_x0 * (-1);
            float tan_y = get_y0*(-1);
            double atan = Math.atan(tan_y / tan_x);
            mPointAngle= (int) Math.toDegrees(atan)+90;
        }

        /*03:右上角区域*/
        if(get_x0>=0&get_y0<=0){
            float tan_x = get_x0 ;
            float tan_y = get_y0*(-1);
            double atan = Math.atan(tan_x/ tan_y);
            mPointAngle= (int) Math.toDegrees(atan)+180;
        }

        /*04:右下角区域*/
        if(get_x0>=0&get_y0>=0){
            float tan_x = get_x0 ;
            float tan_y = get_y0;
            double atan = Math.atan(tan_y / tan_x);
            mPointAngle= (int) Math.toDegrees(atan)+270;
        }

        /*得到点的角度后进行重绘*/
        invalidate();

        return true;
    }

//温度回调的接口
    public interface OnProgressListener{
        public void onScrollingListener(Integer progress);
    }

    /**
     * 设置当前温度
     * @param progerss 应大于等于 startTemporary 小于等于 endTemperature
     */
    private void convertTempToDegree(int progerss) {
        if (progerss <= endTemperature && progerss >= startTemperature) {
            int i = progerss - startTemperature;
            int total = endTemperature - startTemperature;
            float rate = (float)270 / (float)total;
            mPointAngle = (int) (i * rate)+45;//加上起始角度
        }
    }

    /**
     * 设置温度
     * @param temp
     */
    public void setTemperature(int temp) {
        convertTempToDegree(temp);
            invalidate();
    }

}
这里允许我再BB两点

1:onDraw里面的逻辑  :弧形的起始角度为45-315,然后将弧形顺时针旋转90度 (canvas.rotate),画背景灰色的弧度(canvas.drawArc),然后初始化时将温度转换为角度并画上去(canvas.drawArc),这里需要用到SweepGradient 产生颜色渐变的弧度,并把这个设置给画笔,

接下来就要开始画手柄那个点 白色的实心点canvas.drawCircle 然后在用argbEvaluator差值器计算出当前弧度所需要的颜色,并设置给画笔,之后在缩小画笔的尺寸,在画刚才计算出颜色的点.最后在画问题,需要注意的是需要计算下文本的位置paint.getTextBounds

这里有个坑是之前旋转了90度的画布,所以画文本是旋转90度 的,那需要把当前的内容先保存 canvas.save();//保存以上内容,否则写文字会旋转90度 canvas.rotate(-90,width/2,height/2);//旋转画布-90度回到初始时

 
 

2最核心的onTouchEvent 三角函数的计算


这里分别把按下去的点分为4个象限去分别处理,我已第三象限为例子,还特意自己纯手工画了图



       /*获取点击位置的坐标*/
        float down_x = event.getX();
        float down_y = event.getY();

        /*获取三角形两条直角边*/
        float x_height = down_x - x0;
        float y_height = down_y - y0;
        /*01:左下角区域*/
        if(x_height<=0&y_height>=0){
            float tan_x = x_height * (-1);
            float tan_y = y_height;
            double atan = Math.atan(x_height / y_height);
            mPointAngle= (int) Math.toDegrees(atan);//得到相对水平方向的角度
        }




猜你喜欢

转载自blog.csdn.net/qq_35599978/article/details/73431030