Android随笔之简单仪表盘

上个图
微信图片_20201112103153.jpg

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.Rect;

import android.graphics.RectF;

import android.graphics.Typeface;

import android.os.Handler;

import android.support.annotation.Nullable;

import android.util.AttributeSet;

import android.util.DisplayMetrics;

import android.view.View;

import baidertrs.zhijienet.util.DensityUtils;

/**

* Created by RSW on 2018/4/23.

* baidertrs.zhijienet.ui.view.dashboard

*/

public class PanelViewextends Viewimplements Runnable {

private int mWidth;

private int mHeight;

private int screenWidth;//屏幕宽

    private int screenHeight;//屏幕高

    private int mDensityDpi;//屏幕dpi

    private int raduis;//半径

    private int pointX, pointY;//圆心

    private float mStartAngle  =180f;// 起始角度

    private float mSweepAngle  =180f;// 绘制角度

    private float animprogress =0.0f;// 指针动画进度

    Context mContext;

float zhizhenValue =0f;

float jiaodu      =0f;

float jiaodu2      =0f;

private float  mPortion =14;// 一个mSection等分份数

    private float  mSection =7;// 值域(mMax-mMin)等分份数

    private Handler handler  =new Handler();// 用于延时更新,实现动画

// 第一个参数表示角度;负数表示左边球旋转的角度,正数表示右边球旋转的角度

// +angle表示右侧球偏离最大的角度

// -angle表示左侧球偏离最大的角度

// 第二个参数表示方向;-1表示从右往左摆动,1表示从左往右摆动

    private float t =15f;//时间;可以用来控制速率,t越小,摆钟越慢;t越大,摆钟越快

    private float cosO;//cosθ,是个固定值

    private float gr2;//2gr,是个固定值

    private float  angle  =0.8f;//最大旋转角度

    private float[] degree =new float[]{angle, -1};

int flag =0;

Paint bigArcPaint;

Paint keduPaint1, keduPaint2;

Paint outCirclePaint;

Paint numberPaint;

Paint xuxianPaint1, xuxianPaint2;

Paint keduArcPaint1, keduArcPaint2;

Paint smallArcPaint;

Paint zhizhenPaint;

RectF bigArcRectF;

RectF keduRectF;

RectF xuxianRectF;

RectF keduArcRectF;

RectF smallArcRectF;

public float getZhizhenValue() {

return zhizhenValue;

}

public void setZhizhenValue(float zhizhenValue) {

//        if (Build.VERSION.SDK_INT > 23) {

//            t = 7.5f;

//        } else {

//            t = 15f;

//        }

        System.out.println("zhizhenValue=============="+zhizhenValue);

flag =0;

this.zhizhenValue = zhizhenValue;

animprogress =0.0f;

invalidate();

}

public PanelView(Context context) {

this(context,null);

calCosOAnd2gr();

}

public PanelView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs,0);

calCosOAnd2gr();

}

public PanelView(Context context, @Nullable AttributeSet attrs,int defStyleAttr) {

super(context, attrs, defStyleAttr);

calCosOAnd2gr();

this.mContext = context;

// TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PanelView, defStyleAttr, 0);

//获取屏幕宽高 和 屏幕密度dpi

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

screenWidth = displayMetrics.widthPixels;

screenHeight = displayMetrics.heightPixels;

mDensityDpi = displayMetrics.densityDpi /320;

//关闭硬件加速

        setLayerType(LAYER_TYPE_SOFTWARE,null);

//初始化 半径

        raduis = screenWidth /3;

//圆心

        pointX = pointY = screenWidth /2;

bigArcRectF =new RectF(pointX - raduis, pointY - raduis, pointX + raduis, pointY + raduis);

bigArcPaint =new Paint();//最外层的半圆画笔

        bigArcPaint.setStrokeWidth(16 * mDensityDpi);

bigArcPaint.setStrokeCap(Paint.Cap.ROUND);//设置画笔笔触为圆形

        bigArcPaint.setAntiAlias(true);

bigArcPaint.setStyle(Paint.Style.STROKE);

bigArcPaint.setColor(Color.parseColor("#ffffff"));

bigArcPaint.setAlpha(100);

keduRectF =new RectF(pointX - raduis, pointY - raduis, pointX + raduis, pointY + raduis);

keduPaint1 =new Paint();

keduPaint1.setStyle(Paint.Style.STROKE);

keduPaint1.setAntiAlias(true);

// p.setShadowLayer(3F, 2F, 2F, Color.parseColor("#FFF03B"));

        keduPaint1.setColor(Color.parseColor("#FFF03B"));

keduPaint1.setStrokeWidth(16 * mDensityDpi);

keduPaint1.setStrokeCap(Paint.Cap.ROUND);//设置画笔笔触为圆形

        keduPaint2 =new Paint();

keduPaint2.setStyle(Paint.Style.STROKE);

keduPaint2.setAntiAlias(true);

keduPaint2.setColor(Color.parseColor("#FFF03B"));

keduPaint2.setStrokeWidth(1 * mDensityDpi);

keduPaint2.setStrokeCap(Paint.Cap.ROUND);//设置画笔笔触为圆形

        keduPaint2.setStyle(Paint.Style.FILL_AND_STROKE);

outCirclePaint =new Paint();

outCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);

outCirclePaint.setAntiAlias(true);

outCirclePaint.setColor(Color.parseColor("#ffffff"));

outCirclePaint.setStrokeWidth(1 * mDensityDpi);

Typeface typeface = Typeface.createFromAsset(mContext.getAssets(),"fonts/Haettenschweiler.ttf");

numberPaint =new Paint();

numberPaint.setStyle(Paint.Style.FILL_AND_STROKE);

numberPaint.setAntiAlias(true);

numberPaint.setColor(Color.parseColor("#ffffff"));

numberPaint.setTypeface(typeface);

numberPaint.setStrokeWidth(1 * mDensityDpi);

numberPaint.setTextAlign(Paint.Align.CENTER);

int strokeWidth = raduis /4;//要绘制圆弧的宽度

        xuxianRectF =new RectF(pointX - raduis +10 *2 * mDensityDpi + strokeWidth /2, pointY - raduis +10 *2 * mDensityDpi + strokeWidth /2,

pointX + raduis -10 *2 * mDensityDpi - strokeWidth /2, pointY + raduis -10 *2 * mDensityDpi - strokeWidth /2);

xuxianPaint1 =new Paint();

xuxianPaint1.setStyle(Paint.Style.STROKE);

xuxianPaint1.setAntiAlias(true);

xuxianPaint1.setColor(Color.parseColor("#ffffff"));

xuxianPaint1.setAlpha(30);

xuxianPaint1.setStrokeWidth(raduis /4);

xuxianPaint2 =new Paint();

xuxianPaint2.setAntiAlias(true);

xuxianPaint2.setColor(Color.parseColor("#ffffff"));

xuxianPaint2.setStyle(Paint.Style.STROKE);

xuxianPaint2.setAlpha(100);

xuxianPaint2.setStrokeWidth(5 * mDensityDpi);

keduArcRectF =new RectF(pointX - raduis /2 + raduis /4 /2, pointY - raduis /2 + raduis /4 /2,

pointX + raduis /2 - raduis /4 /2, pointY + raduis /2 - raduis /4 /2);

keduArcPaint1 =new Paint();

keduArcPaint1.setStyle(Paint.Style.STROKE);

keduArcPaint1.setAntiAlias(true);

keduArcPaint1.setColor(Color.parseColor("#F3612B"));

keduArcPaint1.setStrokeWidth(raduis /4);

keduArcPaint2 =new Paint();

keduArcPaint2.setStyle(Paint.Style.STROKE);

keduArcPaint2.setAntiAlias(true);

keduArcPaint2.setColor(Color.parseColor("#c21212"));

keduArcPaint2.setAlpha(50);

keduArcPaint2.setStrokeWidth(3 * mDensityDpi);

smallArcRectF =new RectF(pointX - raduis /4 + mDensityDpi /2, pointY - raduis /4 + mDensityDpi /2,

pointX + raduis /4 - mDensityDpi /2, pointY + raduis /4 - mDensityDpi /2);

smallArcPaint =new Paint();

smallArcPaint.setStyle(Paint.Style.FILL);

smallArcPaint.setAntiAlias(true);

smallArcPaint.setColor(Color.parseColor("#FC8248"));

smallArcPaint.setStrokeWidth(mDensityDpi);

zhizhenPaint =new Paint();

zhizhenPaint.setStyle(Paint.Style.FILL);

zhizhenPaint.setAntiAlias(true);

zhizhenPaint.setColor(Color.parseColor("#FFF0E9"));

zhizhenPaint.setStrokeWidth(mDensityDpi);

}

/**

* 用来计算cosθ和2gr

*/

    private void calCosOAnd2gr() {

//这里为了避免cosα-cosθ=0的情况,所以+0.1

        cosO = (float) Math.cos((angle +0.1f) * Math.PI /180);

//2倍的重力加速度乘以半径

        gr2 = (float) (9.8 * raduis *2);

}

@Override

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

if (widthMode == MeasureSpec.EXACTLY) {

mWidth = widthSize;

}else {

// mWidth = DensityUtils.dp2px(mContext, 200);

            mWidth = screenWidth;

}

if (heightMode == MeasureSpec.EXACTLY) {

mHeight = heightSize;

}else {

// mHeight = DensityUtils.dp2px(mContext, 200);

            mHeight = screenHeight /3;

}

setMeasuredDimension(mWidth, mHeight);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (flag ==1) {//表示指针已经第一次完成数据加载,到达指定位置

            jiaodu2 = (animprogress + degree[0]) * mSweepAngle /100 -1f;

}else {//开始进行小幅度左右摆动

            jiaodu = (animprogress) * mSweepAngle /100;

}

handler.postDelayed(this,1);

drawBigArc(canvas);//最外层的半圆

        drawkedu(canvas);//最外层的半圆的刻度

        drawOutCircle(canvas);//最外层半圆的白点刻度

        drawNumber(canvas);//最外层刻度数字

        drawxuxian(canvas);//透明圆弧和里面的虚线

        drawkeduArc(canvas);//画带刻度的圆弧和刻度

        drawsmallArc(canvas);//画最小的半圆

        drawzhizhen(canvas);//画指针

        if (degree[1] ==1) {

//从左往右,degree增大

            if (degree[0] < angle) {

//计算需要转动的角度

                float changeAngle = rotateAngle();

//改变当前角度的值

                degree[0] = degree[0] + changeAngle;

invalidate();

}

//当达到最右侧时,方向翻转

            if (degree[0] >= angle) {

degree[1] = -1;

}

}else if (degree[1] == -1) {

//从右往左,degree减小

            if (degree[0] > -angle) {

//计算需要转动的角度

                float changeAngle = rotateAngle();

//改变当前角度的值

                degree[0] = degree[0] - changeAngle;

invalidate();

}

//当达到最左侧时,方向翻转

            if (degree[0] <= -angle) {

degree[1] =1;

}

}

}

/**

* 计算当前需要转动的角度

*

    * @return

    */

    private float rotateAngle() {

//计算当前的速率

        float v = (float) Math.sqrt(gr2 * (Math.cos(Math.abs(degree[0]) * Math.PI /180) - cosO));

//计算需要改变的弧度

        float changedAngle = t * v / raduis;

return changedAngle;

}

private void drawzhizhen(Canvas canvas) {

float angle;

if (flag ==1) {//当flag==1时,表示指针需要摆动了,所以angle取jiaodu2,带摆动的值

            angle = jiaodu2;

}else {

angle = jiaodu;

}

float r = raduis /12;

float strokeWidth = mDensityDpi;//要绘制圆弧的宽度

        canvas.drawCircle(pointX, pointY, r, zhizhenPaint);

float sweepAngle =15f;

float r1 =20;

float[] point_r1 = getCoordinatePoint(r1 + r, mStartAngle + angle - sweepAngle);

float[] point_r2 = getCoordinatePoint(raduis -30 * mDensityDpi - strokeWidth /5, mStartAngle + angle);

float[] point_r3 = getCoordinatePoint(r1 + r, mStartAngle + angle + sweepAngle);

// 画指针

        Path mPath =new Path();

mPath.moveTo(pointX, pointY);

mPath.lineTo(point_r1[0], point_r1[1]);

mPath.lineTo(point_r2[0], point_r2[1]);

mPath.lineTo(point_r3[0], point_r3[1]);

mPath.lineTo(pointX, pointY);

mPath.close();

canvas.drawPath(mPath, zhizhenPaint);

}

private void drawsmallArc(Canvas canvas) {

canvas.drawArc(smallArcRectF, mStartAngle, mSweepAngle,false, smallArcPaint);

}

private void drawkeduArc(Canvas canvas) {

int strokeWidth = raduis /4;//要绘制圆弧的宽度

        canvas.drawArc(keduArcRectF, mStartAngle, mSweepAngle,false, keduArcPaint1);

//画刻度

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

float[] point = getCoordinatePoint(raduis /2, mStartAngle + mSweepAngle /35 * i);

float[] point1 = getCoordinatePoint(raduis /2 - strokeWidth /3, mStartAngle + mSweepAngle /35 * i);

float[] point2 = getCoordinatePoint(raduis /2 - strokeWidth /4, mStartAngle + mSweepAngle /35 * i);

if (i %5 ==0) {//画长刻度

                canvas.drawLine(point[0], point[1], point1[0], point1[1], keduArcPaint2);

}else {//画短刻度

                canvas.drawLine(point[0], point[1], point2[0], point2[1], keduArcPaint2);

}

}

}

private void drawxuxian(Canvas canvas) {

int strokeWidth = raduis /4;//要绘制圆弧的宽度

        canvas.drawArc(xuxianRectF, mStartAngle -1, mSweepAngle +2,false, xuxianPaint1);

for (int i =0; i <= mSection * mPortion; i++) {//画小虚线

            float[] point = getCoordinatePoint(raduis -10 * mDensityDpi - strokeWidth /5, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

float[] point1 = getCoordinatePoint(raduis -10 * mDensityDpi - strokeWidth /5 -4 * mDensityDpi, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

float[] point2 = getCoordinatePoint(raduis -10 * mDensityDpi -2 * strokeWidth /5, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

float[] point3 = getCoordinatePoint(raduis -10 * mDensityDpi -2 * strokeWidth /5 -4 * mDensityDpi, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

float[] point4 = getCoordinatePoint(raduis -10 * mDensityDpi -3 * strokeWidth /5, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

float[] point5 = getCoordinatePoint(raduis -10 * mDensityDpi -3 * strokeWidth /5 -4 * mDensityDpi, mStartAngle + mSweepAngle / (mSection * mPortion) * i);

canvas.drawLine(point[0], point[1], point1[0], point1[1], xuxianPaint2);

if ((i >1 * mPortion && i < mPortion *2) || (i >5 * mPortion && i < mPortion *6)) {

}else {

canvas.drawLine(point2[0], point2[1], point3[0], point3[1], xuxianPaint2);

}

if ((i >8 && i <16) || (i >4 * mPortion && i < mPortion *6)) {

}else {

canvas.drawLine(point4[0], point4[1], point5[0], point5[1], xuxianPaint2);

}

}

}

private void drawNumber(Canvas canvas) {

Rect bounds =new Rect();

for (int i =0; i < mSection +1; i++) {

String testString =50 * i +"";

float[] point = getCoordinatePoint(raduis +70 * mDensityDpi, mStartAngle + i * (float) (mSweepAngle / mSection));

if (jiaodu >= i * (float) (mSweepAngle / mSection)) {

numberPaint.setAlpha(255);

numberPaint.setTextSize(DensityUtils.sp2px(mContext,16));

}else {

numberPaint.setAlpha(100);

numberPaint.setTextSize(DensityUtils.sp2px(mContext,10));

}

numberPaint.getTextBounds(testString,0, testString.length(), bounds);

if (i <4) {

canvas.drawText(testString, point[0] - bounds.width() /2, point[1] + bounds.height() /2, numberPaint);

}else {

canvas.drawText(testString, point[0] + bounds.width() /2, point[1] + bounds.height() /2, numberPaint);

}

}

}

private void drawOutCircle(Canvas canvas) {

//        for (int i = 0; i < mSection + 1; i++) {

//            //指针扫过角度的圆点

//            float[] point = getCoordinatePoint(raduis + 25 * mDensityDpi, mStartAngle + i * (float) (mSweepAngle / mSection));

//            canvas.drawCircle(point[0], point[1], 10 * mDensityDpi, p);

//        }

        for (int i =0; i <=5 * mSection; i++) {

float[] point = getCoordinatePoint(raduis +35 * mDensityDpi, mStartAngle + i * (float) (mSweepAngle / (mSection *5)));

if (jiaodu >= i * (float) (mSweepAngle / (mSection *5))) {

outCirclePaint.setAlpha(255);

}else {

outCirclePaint.setAlpha(100);

}

if (i %5 ==0) {

//指针扫过角度的大圆点

                canvas.drawCircle(point[0], point[1],6 * mDensityDpi, outCirclePaint);

}else {

//指针扫过角度的小圆点

                canvas.drawCircle(point[0], point[1],3 * mDensityDpi, outCirclePaint);

}

}

}

private void drawkedu(Canvas canvas) {

canvas.drawArc(keduRectF, mStartAngle, jiaodu,false, keduPaint1);

//指针扫过角度的圆点

        float[] point = getCoordinatePoint(raduis, mStartAngle + jiaodu);

canvas.drawCircle(point[0], point[1],15 * mDensityDpi, keduPaint2);

}

private void drawBigArc(Canvas canvas) {

canvas.drawArc(bigArcRectF, mStartAngle, mSweepAngle,false, bigArcPaint);

}

//将角度和半径转为点

    private float[] getCoordinatePoint(float radius,float angle) {

float[] point =new float[2];

double arcAngle = Math.toRadians(angle);//将角度转换为弧度

        if (angle <90) {

point[0] = (float) (pointX + Math.cos(arcAngle) * radius);

point[1] = (float) (pointY + Math.sin(arcAngle) * radius);

}else if (angle ==90) {

point[0] = pointX;

point[1] = pointY + radius;

}else if (angle >90 && angle <180) {

arcAngle = Math.PI * (180 - angle) /180.0;

point[0] = (float) (pointX - Math.cos(arcAngle) * radius);

point[1] = (float) (pointY + Math.sin(arcAngle) * radius);

}else if (angle ==180) {

point[0] = pointX - radius;

point[1] = pointY;

}else if (angle >180 && angle <270) {

arcAngle = Math.PI * (angle -180) /180.0;

point[0] = (float) (pointX - Math.cos(arcAngle) * radius);

point[1] = (float) (pointY - Math.sin(arcAngle) * radius);

}else if (angle ==270) {

point[0] = pointX;

point[1] = pointY - radius;

}else {

arcAngle = Math.PI * (360 - angle) /180.0;

point[0] = (float) (pointX + Math.cos(arcAngle) * radius);

point[1] = (float) (pointY - Math.sin(arcAngle) * radius);

}

return point;

}

@Override

public void run() {

if (animprogress >= zhizhenValue) {

flag =1;

invalidate();

return;

}else {

animprogress +=1;

invalidate();

}

}

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容