Android 自定义码表图

项目里面又碰到一个酷炫的刻度盘,还要带平滑动画的,真伤脑筋啊,网上搜索半天无果,果然还是得自己动手啊。

用时半天,做了一个DEMO,效果图如下:

Android 自定义码表图

 

 

代码如下,复制粘贴就能跑了:

MeterView.java:

 

/**

 * Copyright (C) 2015

 *

 * MeterView.java

 *

 * Description: 

 *

 * Author: Liao Longhui 

 *

 * Ver 1.0, 2015-05-17, Liao Longhui, Create file

 */



package com.example.test;



import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Paint.Align;

import android.util.AttributeSet;

import android.view.View;

import android.widget.Scroller;



import java.util.ArrayList;

import java.util.List;



/**

 * 半圆码表图

 * @author LLH

 *

 */

public class MeterView extends View {



    /**

     * 刻度颜色

     */

    private int mDegreeColor = Color.LTGRAY;



    /**

     * 主刻度颜色

     */

    private int mMajorDegreeColor = Color.GRAY;



    /**

     * 刻度数颜色

     */

    private int mDegreeTextColor = Color.BLUE;



    /**

     * 刻度数大小(px)

     */

    private int mDegreeTextSize;



    /**

     * 当前数值文字大小(px)

     */

    private int mContentTextSize;



    /**

     * 当前数值文字颜色

     */

    private int mContentTextColor = Color.BLUE;



    /**

     * 单位文字大小(px)

     */

    private int mUnitTextSize;



    /**

     * 单位文字颜色

     */

    private int mUnitTextColor = Color.RED;



    /**

     * 标题文字颜色

     */

    private int mTitleTextColor = Color.BLUE;



    /**

     * 标题文字大小(px)

     */

    private int mTitleTextSize;



    /**

     * 刻度渐变色起始RGB值

     */

    private int startColor_r = 0x00;

    private int startColor_g = 0xFF;

    private int startColor_b = 0x00;

    private int endColor_r = 0xFF;

    private int endColor_g = 0x00;

    private int endColor_b = 0x00;



    private Paint mDegreePaint;



    private Paint mMajorDegreePaint;



    private Paint mColorDegreePaint;



    private Paint mUnitPaint;



    private Paint mContentTextPaint;



    private Paint mDegreeTextPaint;



    private Paint mTitleTextPaint;



    /**

     * 当前数值

     */

    private float mContent = 0;



    /**

     * 前一数字对应的刻度索引

     */

    private int mLastDegreeIndex;



    private String mUnit = "W";



    private String mTiltl = "当前功率";



    /**

     * 刻度主刻度数据

     */

    private List<String> mDegrees = new ArrayList<String>();



    /**

     * 刻度最大值和最小值

     */

    private float degreeMax, degreeMin;



    /**

     * 刻度长度

     */

    private int mDegreeLen;



    /**

     * 刻度盘各刻度线的信息

     */

    private List<DegreeLine> mDegreeLines;



    private int width, height;

    private int radius;

    private int xPoint, yPoint;

    private float density;

    private Scroller mScroller;



    public MeterView(Context context, AttributeSet attrs) {

        super(context, attrs);

        density = getResources().getDisplayMetrics().density;

        mScroller = new Scroller(context);



    }



    public MeterView(Context context) {

        super(context);

    }



    private void initPaint() {

        mDegreeTextSize = radius / 10;

        mContentTextSize = radius / 4;

        mUnitTextSize = radius / 6;

        mTitleTextSize = radius / 8;



        mDegreePaint = new Paint();

        mDegreePaint.setStyle(Paint.Style.FILL);

        mDegreePaint.setAntiAlias(true);

        mDegreePaint.setColor(mDegreeColor);

        mDegreePaint.setStrokeWidth(2f * density);



        mMajorDegreePaint = new Paint();

        mMajorDegreePaint.setStyle(Paint.Style.FILL);

        mMajorDegreePaint.setAntiAlias(true);

        mMajorDegreePaint.setColor(mMajorDegreeColor);

        mMajorDegreePaint.setStrokeWidth(2.5f * density);



        mColorDegreePaint = new Paint();

        mColorDegreePaint.setStyle(Paint.Style.FILL);

        mColorDegreePaint.setAntiAlias(true);

        mColorDegreePaint.setStrokeWidth(2.5f * density);



        mUnitPaint = new Paint();

        mUnitPaint.setStyle(Paint.Style.FILL);

        mUnitPaint.setAntiAlias(true);

        mUnitPaint.setColor(mUnitTextColor);

        mUnitPaint.setStrokeWidth(2);

        mUnitPaint.setTextAlign(Align.CENTER);

        mUnitPaint.setTextSize(mUnitTextSize);



        mContentTextPaint = new Paint();

        mContentTextPaint.setStyle(Paint.Style.FILL);

        mContentTextPaint.setAntiAlias(true);

        mContentTextPaint.setColor(mContentTextColor);

        mContentTextPaint.setStrokeWidth(2);

        mContentTextPaint.setTextAlign(Align.CENTER);

        mContentTextPaint.setTextSize(mContentTextSize);



        mDegreeTextPaint = new Paint();

        mDegreeTextPaint.setStyle(Paint.Style.FILL);

        mDegreeTextPaint.setAntiAlias(true);

        mDegreeTextPaint.setColor(mDegreeTextColor);

        mDegreeTextPaint.setStrokeWidth(2);

        mDegreeTextPaint.setTextAlign(Align.CENTER);

        mDegreeTextPaint.setTextSize(mDegreeTextSize);



        mTitleTextPaint = new Paint();

        mTitleTextPaint.setStyle(Paint.Style.FILL);

        mTitleTextPaint.setAntiAlias(true);

        mTitleTextPaint.setColor(mTitleTextColor);

        mTitleTextPaint.setStrokeWidth(2);

        mTitleTextPaint.setTextSize(mTitleTextSize);

    }



    @Override

    public void computeScroll() {

        super.computeScroll();

        if (mScroller.computeScrollOffset()) {

            int x = mScroller.getCurrX();

            for (int i = 0; i < mDegreeLines.size(); i++) {

                if (i <= x) {

                    mDegreeLines.get(i).showColor = true;

                } else {

                    mDegreeLines.get(i).showColor = false;

                }

            }

            postInvalidate();

        }

    }



    @Override

    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        for (int i = 0; i < mDegreeLines.size(); i++) {

            if (mDegreeLines.get(i).showColor) {

                mColorDegreePaint.setColor(mDegreeLines.get(i).color);

            }

            canvas.drawLine(mDegreeLines.get(i).x1, mDegreeLines.get(i).y1,

                    mDegreeLines.get(i).x2, mDegreeLines.get(i).y2,

                    mDegreeLines.get(i).showColor ? mColorDegreePaint

                            : (mDegreeLines.get(i).isMajor ? mMajorDegreePaint : mDegreePaint));

            if (mDegreeLines.get(i).isMajor) {

                int x = (int) ((5 * mDegreeLines.get(i).x2 - 2 * mDegreeLines.get(i).x1) / 3);

                int y = (int) ((5 * mDegreeLines.get(i).y2 - 2 * mDegreeLines.get(i).y1) / 3);

                canvas.drawText(mDegrees.get(i / 10), x, y, mDegreeTextPaint);

            }

        }

        canvas.drawText(mTiltl, 0, mTitleTextSize, mTitleTextPaint);

        canvas.drawText(mUnit, xPoint, yPoint, mUnitPaint);

        canvas.drawText(String.valueOf(mContent), xPoint, yPoint - mUnitTextSize - 5 * density,

                mContentTextPaint);

    }



    @Override

    protected void onLayout(boolean changed, int left, int top, int right,

            int bottom) {

        super.onLayout(changed, left, top, right, bottom);

        initPaint();

        initDegrees();

    }



    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        density = getResources().getDisplayMetrics().density;

        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

        height = getDefaultSize(getSuggestedMinimumWidth(), heightMeasureSpec);

        if (width / 2 + 15 * density < height) {

            height = (int) (width / 2 + 15 * density);

        } else {

            width = (int) ((height - 15 * density) * 2);

        }

        radius = (int) (width / 2 - 1 * density);

        xPoint = width / 2;

        yPoint = (int) (height - 1 * density);

        setMeasuredDimension(width, height);

    }



    /**

     * 设置当前刻度数值

     * 

     * @param content

     */

    public void setContent(float content) {

        this.mContent = content;

        changeDegree();

    }



    public float getContent() {

        return mContent;

    }



    /**

     * 设置主刻度数值

     * 

     * @param degrees

     */

    public void setDegrees(List<String> degrees, float degreeMax, float degreeMin) {

        this.mDegrees = degrees;

        this.degreeMax = degreeMax;

        this.degreeMin = degreeMin;

        mDegreeLen = degrees.size();

        mLastDegreeIndex = 0;

        mContent = 0;

        initDegrees();

        invalidate();

    }



    public String getTiltl() {

        return mTiltl;

    }



    /**

     * 设置标题

     * 

     * @param mTiltl

     */

    public void setTiltl(String mTiltl) {

        this.mTiltl = mTiltl;

        invalidate();

    }



    /**

     * 设置小刻度颜色

     * 

     * @param mDegreeColor

     */

    public void setDegreeColor(int mDegreeColor) {

        this.mDegreeColor = mDegreeColor;

        invalidate();

    }



    /**

     * 设置大刻度颜色

     * 

     * @param mMajorDegreeColor

     */

    public void setMajorDegreeColor(int mMajorDegreeColor) {

        this.mMajorDegreeColor = mMajorDegreeColor;

        invalidate();

    }



    /**

     * 设置刻度数值文字颜色

     * 

     * @param mDegreeTextColor

     */

    public void setDegreeTextColor(int mDegreeTextColor) {

        this.mDegreeTextColor = mDegreeTextColor;

        invalidate();

    }



    /**

     * 设置单位颜色

     * 

     * @param mUnitTextColor

     */

    public void setUnitTextColor(int mUnitTextColor) {

        this.mUnitTextColor = mUnitTextColor;

        invalidate();

    }



    /**

     * 设置标题颜色

     * 

     * @param mTitleTextColor

     */

    public void setTitleTextColor(int mTitleTextColor) {

        this.mTitleTextColor = mTitleTextColor;

        invalidate();

    }



    /**

     * 设置标题大小(px)

     * 

     * @param mTitleTextSize

     */

    public void setTitleTextSize(int mTitleTextSize) {

        this.mTitleTextSize = mTitleTextSize;

        invalidate();

    }



    /**

     * 设置单位

     * 

     * @param mUnit

     */

    public void setUnit(String mUnit) {

        this.mUnit = mUnit;

        invalidate();

    }



    private void changeDegree() {

        int degreeIndex = (int) (10f * (mDegreeLen - 1) * (mContent - degreeMin) / (degreeMax - degreeMin));

        mScroller.startScroll(mLastDegreeIndex, 0, degreeIndex - mLastDegreeIndex, 0, 1500);

        mLastDegreeIndex = degreeIndex;

        invalidate();

    }



    private void initDegrees() {

        mDegreeLines = new ArrayList<DegreeLine>();

        double deltaAngle = Math.PI / (10 * (mDegreeLen - 1));

        float deltaColor_r = (endColor_r - startColor_r) / (5f * (mDegreeLen - 1));

        float deltaColor_g = (endColor_g - startColor_g) / (5f * (mDegreeLen - 1));

        float deltaColor_b = (endColor_b - startColor_b) / (10f * (mDegreeLen - 1));

        for (int i = 0; i < 10 * (mDegreeLen - 1) + 1; i++) {

            DegreeLine line = new DegreeLine();

            int smallRadius = 7 * radius / 8;

            int k = -1;

            if (deltaAngle * i > Math.PI / 2) {

                k = 1;

            }

            if (i % 10 == 0) {

                line.isMajor = true;

                smallRadius = 5 * radius / 6;

            }

            line.y1 = (float) (yPoint - radius * Math.sin(deltaAngle * i));

            line.x1 = (float) (k

                    * Math.sqrt(radius * radius - (yPoint - line.y1) * (yPoint - line.y1)) + xPoint);

            line.y2 = (float) (yPoint - smallRadius * Math.sin(deltaAngle * i));

            line.x2 = (float) (k

                    * Math.sqrt(smallRadius * smallRadius - (yPoint - line.y2) * (yPoint - line.y2)) + xPoint);



            int color_r = (int) (startColor_r + i * deltaColor_r);

            int color_g = (int) (startColor_g + i * deltaColor_g);

            int color_b = (int) (startColor_b + i * deltaColor_b);

            if (i < 5 * (mDegreeLen - 1) + 1) {

                color_g = startColor_g;

            } else {

                color_r = endColor_r;

            }

            line.color = Color.rgb(color_r, color_g, color_b);

            mDegreeLines.add(line);

        }

    }



    public class DegreeLine {



        /**

         * 是否大刻度

         */

        public boolean isMajor;



        /**

         * 是否显示颜色

         */

        public boolean showColor;



        /**

         * 颜色

         */

        public int color;



        /**

         * 端点坐标

         */

        public float x1;

        public float y1;

        public float x2;

        public float y2;

    }



}

 

MeterActivity.java:

public class MeterActivity extends Activity {



    protected Toast toast;

    private MeterView meterView;

    private int max = 0;

    private boolean isAlive;



    private Handler mHandler = new Handler() {

        public void handleMessage(Message msg) {

            if (!isAlive) {

                return;

            }

            switch (msg.what) {

                case 1:

                    int num = (int) (Math.random() * max);

                    meterView.setContent(num);

                    mHandler.sendEmptyMessageDelayed(1, 1000);

                    break;



                default:

                    break;

            }

        };

    };



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_meter);

        isAlive = true;

        meterView = (MeterView) findViewById(R.id.meterView1);

        List<String> degrees = new ArrayList<String>();

        degrees.add("0 ");

        degrees.add("20");

        degrees.add("40");

        degrees.add("60");

        degrees.add("80");

        max = 80;

        meterView.setDegrees(degrees, 80f, 0f);

        mHandler.sendEmptyMessageDelayed(1, 1000);



        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                List<String> degrees = new ArrayList<String>();

                for (int i = 0; i < 7; i++) {

                    degrees.add(String.valueOf(20 * i));

                }

                max = 20 * 6;

                degrees.set(0, "0  ");

                meterView.setDegrees(degrees, max, 0);

            }

        });

        findViewById(R.id.button2).setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                List<String> degrees = new ArrayList<String>();

                for (int i = 0; i < 9; i++) {

                    degrees.add(String.valueOf(20 * i));

                }

                max = 20 * 8;

                degrees.set(0, "0  ");

                meterView.setDegrees(degrees, max, 0);

            }

        });

        findViewById(R.id.button3).setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                List<String> degrees = new ArrayList<String>();

                for (int i = 0; i < 10; i++) {

                    degrees.add(String.valueOf(50 * i));

                }

                max = 50 * 9;

                degrees.set(0, "0  ");

                meterView.setDegrees(degrees, max, 0);

            }

        });

        findViewById(R.id.button4).setOnClickListener(new OnClickListener() {



            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                List<String> degrees = new ArrayList<String>();

                for (int i = 0; i < 13; i++) {

                    degrees.add(String.valueOf(50 * i));

                }

                max = 50 * 12;

                degrees.set(0, "0  ");

                meterView.setDegrees(degrees, max, 0);

            }

        });

    }



    @Override

    protected void onDestroy() {

        // TODO Auto-generated method stub

        super.onDestroy();

        isAlive = false;

    }



    public void makeToast(String msg) {

        if (toast == null) {

            toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);

        }

        toast.setText(msg);

        toast.show();

    }

}

activity_meter.xml:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:padding="10dp" >

    

    <TextView

        android:id="@+id/text1" 

        android:layout_width="match_parent"

        android:layout_height="3dp"

        android:background="#abcdef"

        android:layout_centerInParent="true"/>



    <com.example.test.MeterView

        android:id="@+id/meterView1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/text1"

        android:layout_alignParentTop="true"

        android:background="#55abcdef" />



    <Button

        android:id="@+id/button1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/text1"

        android:text="140" />



    <Button

        android:id="@+id/button2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/button1"

        android:layout_below="@+id/button1"

        android:text="180" />



    <Button

        android:id="@+id/button3"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignRight="@+id/button2"

        android:layout_below="@+id/button2"

        android:text="300" />



    <Button

        android:id="@+id/button4"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/button3"

        android:layout_below="@+id/button3"

        android:text="600" />

    

</RelativeLayout>

 

你可能感兴趣的:(android)