美文网首页
自定义圆形空调温度计

自定义圆形空调温度计

作者: baby_double | 来源:发表于2017-11-15 10:25 被阅读0次
     注意: 写该文章主要帮助自己记忆,贴出来希望可以给有同样问题的人解惑,不喜勿喷,可以提意见哦。
    

    一、圆形温度计效果图如下:
    1、当滑块在最低端的时候温度表示18摄氏度,当滑块在最顶端的时候温度表示32摄氏度,滑块每移动一小格,温度增加0.5摄氏度。


    1510552606(1).png
    说明:该图的背景不是代码画出来的,是UI切的图,主要做的就是勾画小滑块,让小滑块沿着有颜色的半圆弧滑动。
    

    二、自定义控件相应方法讲解

       onMeasure
       根据视图的长宽来确定内圆半径,外圆半径,圆心点。
       onDraw
       正真绘制小滑块的方法,根据旋转的角度,绘制滑块的位置。
       onTouchEvent
       当人为的去滑滑动条的时候,就会调用该方法。
       setDegree
       通过该方法设置温度示数,来计算滑块需要旋转的角度。
       flag变量
       用于表示是否要更新滑块的位置,更新滑块的几个条件如下:
       (1)抬手或者取消,都需要更新视图。
       (2)当移动的过程中,超过规定的范围也需要更新视图。
    

    2、自定义圆形温度计实现代码:

     public class TempCircularSeekBar extends View {
    
    private Paint circleColorpaint;
    //绘制滑块的画笔
    private Paint innerColor;
    //滑块需要旋转的角度
    private int angle = 0;
        //圆环的宽度
    private int barWidth = 50;
       //内部圆的半径
    private float innerRadius;
       //外部圆的半径
    private float outerRadius;
       //圆心的x坐标
    private float cx;
        //圆心的y坐标
    private float cy;
        //The left bound for the circle RectF
    private float left;
    //The right bound for the circle RectF
    private float right;
    //The top bound for the circle RectF
    private float top;
    // The bottom bound for the circle RectF
    private float bottom;
    
    
    
    //The adjustment factor. This adds an adjustment of the specified             
         //size to
    private float adjustmentFactor = 100;
    /** The rectangle containing our circles and arcs. */
    private RectF rectcenter = new RectF();
        private TempDegreeCallback degreecallback;
    /**
     * Instantiates a new circular seek bar.
     * 
     * @param context
     *            the context
     * @param attrs
     *            the attrs
     * @param defStyle
     *            the def style
     */
    public TempCircularSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        barWidth = ToolUtils.dip2px(context, 25);
        adjustmentFactor = 80;
        circleColorpaint = new Paint();
        circleColorpaint.setStyle(Paint.Style.STROKE);
        circleColorpaint.setColor(Color.parseColor("#00ffffff"));
        circleColorpaint.setAntiAlias(true);
        innerColor = new Paint();
        innerColor.setStyle(Paint.Style.FILL);
        innerColor.setColor(Color.parseColor("#00ffffff"));                                                 
        innerColor.setAntiAlias(true);
        innerColor.setStrokeWidth(10);
        innerColor.setColor(Color.parseColor("#00ffffff"));
    }
    
    /**
     * Instantiates a new circular seek bar.
     * 
     * @param context
     *            the context
     * @param attrs
     *            the attrs
     */
    public TempCircularSeekBar(Context context, AttributeSet attrs)     
       {
        this(context, attrs,0);
    }
    
    /**
     * Instantiates a new circular seek bar.
     * 
     * @param context
     *            the context
     */
    public TempCircularSeekBar(Context context) {
        this(context,null);
    }
    
    public void setCallback(TempDegreeCallback callback) {
        this.degreecallback = callback;
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int height = MeasureSpec.getSize(heightMeasureSpec);
    
        int size = (width > height) ? height : width; // Choose the smaller
    
        cx = width / 2; // Center X for circle
        cy = height / 2; // Center Y for circle
        outerRadius = (size / 2) - 25; // Radius of the outer circle
    
        innerRadius = outerRadius - barWidth; // Radius of the inner circle
    
        left = cx - outerRadius; // Calculate left bound of our rect
        right = cx + outerRadius;// Calculate right bound of our rect
        top = cy - outerRadius;// Calculate top bound of our rect
        bottom = cy + outerRadius;// Calculate bottom bound of our rect
            rectcenter.set(left, top, right, bottom);
    
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
    
        circleColorpaint.setStrokeWidth(barWidth);
        if (angle > 201) {
            angle = 201;
        }
        // 画内部填充的圆形
        canvas.drawArc(rectcenter, 0, 360, false, circleColorpaint);
        canvas.restore();
        if (angle <= 201 && angle >= 0) {
            float toCenter = outerRadius;
            double miniDegree = Math.PI * (270 - angle) / 180;
            float leftMini = (int) (toCenter * Math.cos(miniDegree)) + left + toCenter;
            float topMini = -(int) (toCenter * Math.sin(miniDegree)) + top + toCenter;
            // 滑动圆心坐标
            // 根据滑动圆心坐标 计算长方形四个角的坐标(设 长方形 长度为l 高度为h)
            int lenth = 28;//小滑块的高
            int width = 13;//小滑块的宽
            double pathDegree;
            if (angle >= 90) {
                pathDegree = Math.PI * (angle - 90) / 180;
            } else {
                pathDegree = Math.PI * (angle + 90) / 180;
            }
    
            float x1 = (int) (leftMini - lenth * Math.cos(pathDegree) - width * Math.sin(pathDegree));
            float y1 = (int) (topMini - lenth * Math.sin(pathDegree) + width * Math.cos(pathDegree));
            float x2 = (int) (leftMini - lenth * Math.cos(pathDegree) + width * Math.sin(pathDegree));
            float y2 = (int) (topMini - lenth * Math.sin(pathDegree) - width * Math.cos(pathDegree));
            float x3 = (int) (leftMini + lenth * Math.cos(pathDegree) + width * Math.sin(pathDegree));
            float y3 = (int) (topMini + lenth * Math.sin(pathDegree) - width * Math.cos(pathDegree));
            float x4 = (int) (leftMini + lenth * Math.cos(pathDegree) - width * Math.sin(pathDegree));
            float y4 = (int) (topMini + lenth * Math.sin(pathDegree) + width * Math.cos(pathDegree));
    
            Log.e("rectcenterminicircle", "滑动角度 :" + angle + " 滑块偏移角度 :" + miniDegree * 180 / Math.PI + " 圆心 :" + leftMini
                    + "---" + topMini + "------长方形 :" + "(" + x1 + "," + y1 + ")" + "  (" + x2 + "," + y2 + ")" + "  (" + x3
                    + "," + y3 + ")" + "  (" + x4 + "," + y4 + ")");
            // 由于画布不能直接画长方形 只能通过画线包裹成一个长方形
            Path path = new Path();
            path.moveTo(x1, y1);
            path.lineTo(x2, y2);
            path.lineTo(x3, y3);
            path.lineTo(x4, y4);
            path.moveTo(x1, y1);
            path.close();
    
            innerColor.setStyle(Paint.Style.FILL);
            innerColor.setColor(Color.parseColor("#99F7F9Fd"));
            canvas.drawPath(path, innerColor);
        }
        canvas.save();
        canvas.translate(cx, cy);
        float roteangle = 180;//
        canvas.rotate(roteangle);
        canvas.restore();
        super.onDraw(canvas);
    }
    
    /**
     * Set the degree.
     * 
     * @param degree
     *            the new degree
     */
    public void setDegree(float degree) {
        int angle = (int) ((degree - 18) * 2 * 7);
        Log.d("Tests", "setDegree angle="+angle);
        //防止滑块滑不到最顶部
        if(angle==196){
            this.angle=201;
        }else {
            this.angle = angle;
        }
        invalidate();
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        flag=false;
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            flag=false;
            //当抬手的时候更新
            moved(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            flag=false;
            float distance = (float) Math.sqrt(Math.pow((x - cx), 2) + Math.pow((y - cy), 2));
            if (distance > outerRadius + (adjustmentFactor-15) || distance < innerRadius - (adjustmentFactor-15)){
                flag=true;          
            }
            moved(x, y);
            break;
        case MotionEvent.ACTION_UP:
            flag=true;
            moved(x, y);
            break;
    
        case MotionEvent.ACTION_CANCEL:
            flag=true;
            moved(x, y);
            break;
        }
        return true;
    }
    
    /**
     * Moved.
     * 
     * @param x
     *            the x
     * @param y
     *            the y
     */
    private void moved(float x, float y) {
        float distance = (float) Math.sqrt(Math.pow((x - cx), 2) + Math.pow((y - cy), 2));
        if (distance < outerRadius + adjustmentFactor && distance > innerRadius - adjustmentFactor) {
            float degrees = (float) ((float) ((Math.toDegrees(Math.atan2(cx - x, y - cy)) + 360.0)) % 360.0);
            if (degrees < 0) {
                degrees += 2 * Math.PI;
            }
            if (degrees <= 250||degrees>=315&&degrees<=360) {
                
                if(degrees>=315&&degrees<=360){
                    degrees=0;
                    flag=true;
                }else if(degrees>=200&&degrees<=250){
                    degrees=200;
                    flag=true;
                }           
                int angle = Math.round(degrees);
                if (angle < 0)
                    angle = 0;
                // 0-210°是滑动范围 根据自己要分割的刻度 一等份角度数 text是刻度 452行有刻度的画法和分割规律
                float temp = (float)(((angle + 3) / 7) * 0.5 + 18);
                if(temp>32){
                    temp=32;
                }
                //根据温度计算滑动的角度
                setDegree(temp);
                //当抬手或者滑出了边际则调到该函数
                if (this.degreecallback != null&&flag) {
                    this.degreecallback.Degree(temp);
                    flag=false;
                }
            }   
        }
    }
       //更加温度值,设置角度
    public abstract interface TempDegreeCallback {
        public abstract void Degree(float degree);
    
    }}
    

    布局文件:

      <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/temperature_bg" >
    <com.hwatong.kongtiaoxiugai_12a.TempCircularSeekBar
        android:id="@+id/temp_seekbar"
        android:layout_width="279dp"
        android:layout_height="280dp"
        android:background="@drawable/temperature_bg" />
    
    <TextView
        android:id="@+id/temperature_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/mintempnum"
        android:textColor="@color/white_air"
        android:textSize="25sp" />
    
    <ImageButton
        android:id="@+id/temperature_up_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="-40dp"
        android:background="@drawable/up_selector" />
    
    <ImageButton
        android:id="@+id/temperature_down_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        android:background="@drawable/down_selector" />
    </FrameLayout>
    

    使用自定义控件的文件

    public class MainActivity extends Activity{
    private TempCircularSeekBar mTempCircularSeekBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.airconditional_main);
                mTempCircularSeekBar = (TempCircularSeekBar)          findViewById(R.id.temp_seekbar);
                       
            mTempCircularSeekBar.setCallback(mTempDegreeCallback);
            //根据温度改变滑块的位置。
             mTempCircularSeekBar.setDegree(32);
        }
    
    TempDegreeCallback mTempDegreeCallback = new         TempDegreeCallback() {
        @Override
        public void Degree(float degree) {
               //在这里可以根据滑块的角度设置温度值
            }};
    

    }

    相关文章

      网友评论

          本文标题:自定义圆形空调温度计

          本文链接:https://www.haomeiwen.com/subject/fboamxtx.html