Android 自定义码表图

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

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

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

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>
时间: 2024-10-12 22:44:25

Android 自定义码表图的相关文章

android 自定义折线图

看图: 比较简陋,主要是通过canvas画上去的: package com.example.democurvegraph.view; import java.util.ArrayList; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Attribute

android自定义折线图

BrokenLine控件: import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import android.content.Context; im

Android自定义view之绘制实用型的柱形图和折线图

概述: 前几天突然需要做两种图表--柱形图.折线图,于是第一反应是先看看网上有没有现成的,结果有是有,但都不是我想要的,而且大多数不是用纯android代码完成,HTML5似乎完成这类工作要容易得多,但是我本人并不会HTML5,只能黯然神伤,掩面流泪,最终只能自己敲代码了. **知识点:**android自定义view.图形图像.Fragment.MVC模式. Demo 界面是模仿红圈营销搭建的 折线图: 代码,注释很详细,直接看代码就行了: public class LineChartView

Android自定义View——实现理财类APP七日年化收益折线图效果

这段时间的自定义View学习,学会了绘制柱状图.绘制折线图.绘制进度控件,那我们今天就来聊聊另外一种自定义的View,这就是我们常见的七日年化收益折线图效果.先看看长什么样. 这就是效果图了,元素相对而言还是比较多的,这里有线.柱状图.文字.折线.点等等.看起来好像很复杂,但是呢,只要一步一步的实现,那还是可以达到这种效果的,之前我们说过的, 自定义View,就像是在photo shop里面画图,想要什么就画什么,我们可以有很多的画笔工具,也可以有很多的图层. 先看看我们这一次用到哪些变量. p

Android自定义组件系列【9】——Canvas绘制折线图

有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas绘制折线图.先看看绘制的效果: 实现原理很简单,我就直接给出代码: package com.example.testcanvasdraw; import java.util.ArrayList; import java.util.List; import java.util.Random; impo

Android 自定义Gallery浏览图片

之前写的<Android ImageSwitcher和Gallery的使用>一文中提到我在教室一下午为实现那个效果找各种资料.期间在网上找了一个个人觉得比较不错的效果,现在贴图上来: 其实这个效果使用的知识点就是图像的获取.创建.缩放.旋转.Matrix类.Canvas类等,另外就是自定义的Gallery控件. 相信大家都期待马上上代码了吧,嘻嘻.(注释比较多,相信大家都能看懂.) main.xml: <?xml version="1.0" encoding=&quo

Android自定义视图四:定制onMeasure强制显示为方形

这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三:给自定义视图添加"流畅"的动画 Android自定义视图四:定制onMeasure强制显示为方形 上一篇开发之后的效果如上图.不过看着这张图,需要注意的不是我们自定义视图展示了什么,而是这个视图的大小和位置.你会看到这个折线图有一个特定的大小(size).这个size是怎么定的呢?现在的代

android自定义Activity窗体大小

先给大家看图吧: 看,是不是很酷呢,呵呵. 这里我说关键的地方,就是自定义Activity的窗体大小. 这个登录框它不是一个Dialog,而是一个Activity. 如何定义,即把Activity的主题设置为Theme.Dialog <activity android:name=".AlertDialogActivity"  android:theme="@style/mytheme" /> mytheme.xml是我自定义的主题 mytheme.xml

Android自定义单选,自定义选中状态

如图,此布局用GrildView实现,弹出框由Activity的dialog样式实现. 屏蔽系统GrildView点击背景黄色: grildview.setSelector(new ColorDrawable(Color.TRANSPARENT)); 实现数据源自定义Adapter public class PeoPleNumAdapter extends BaseAdapter { public List<PeopleNum> FiltArray; public static HashMap