文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android自定义View实践 空气质量检测 pm2.5

2022-06-06 13:05

关注

直接先看效果图
在这里插入图片描述

自定义气体检测视图我们先整理下需要做的的事情 画五个圆弧 每个圆弧上再通过具体的数据绘制一定角度的圆弧 甲醛那个进度条比较特殊,一头平一头椭圆该怎么实现? 文字的绘制 明白了需求我们开搞

画背景圆弧很简单canvas.drawArc 参数分别是圆弧所在的矩形范围、圆弧绘制的其实角度、圆弧划过的角度,是否扫过圆心

  public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
        throw new RuntimeException("Stub!");
    }

在这里插入图片描述
好,那我们先定义加个正方形的宽度 为了适配我引用了AutoSize框架,你可以不用理会。

   float[] whiteCircle  = new float[]{AutoSizeUtils.dp2px(getContext(), 192),
                AutoSizeUtils.dp2px(getContext(), 208),
                AutoSizeUtils.dp2px(getContext(), 226), AutoSizeUtils.dp2px(getContext(), 244)};

宽度有了我们是不是要计算每个正方形放在屏幕中心是的位置也就是第一个参数RectF的构造
首先获取屏幕的宽高

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mMeasureWidth = getMeasuredWidth();
        mMeasureHeight = getMeasuredHeight();
    }

然后构造这个RectF

  public RectF(float left, float top, float right, float bottom) {
        throw new RuntimeException("Stub!");
    }

在这里插入图片描述
看懂了吧 上下左右分别对应的长度如图所示,再看不懂就自己消化下!

那么得出

float left = mMeasureWidth / 2 - 正方形宽 / 2
float top = mMeasureHeight / 2 - 正方形宽 / 2
float right = mMeasureWidth / 2 + 正方形宽 / 2
float left = mMeasureHeight / 2 + 正方形宽 / 2
RectF rect = new RectF(mMeasureWidth / 2 - progressR / 2,
                        mMeasureHeight / 2 - progressR / 2,
                        mMeasureWidth / 2 + progressR / 2,
                        mMeasureHeight / 2 + progressR / 2);

第一个参数搞定,起始角度90度 划过的角度270。不划过圆心。画笔

  Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
  paint.setStyle(Paint.Style.STROKE);/描边模式
  paint.setColor(Color.parseColor("#958280"));//灰色圆弧
  paint.setStrokeWidth(grayPaintWidth);//圆弧宽度
  paint.setStrokeCap(Paint.Cap.BUTT);//两头方形
  canvas.drawArc(rect, 90, 270, false, paint);//最终绘制好一个圆弧
那么接下来开始绘制进度条,除了甲醛的其他都好办,改变画笔颜色按角度绘制就行了
//绘制白色圆
                paint.setColor(Color.WHITE);
                paint.setStrokeWidth(whitePaintWidth);
                float arc = 270 * gasData.getProgress() / gasData.getMax();
                if(arc>270) arc = 270;
                paint.setColor(Color.WHITE);
                paint.setStrokeWidth(4);
                canvas.drawArc(rect, 90, arc, false, paint);
甲醛这个该咋整?

画笔有个属性可以设置椭圆或者方形,但是貌似没有一边圆弧一边方形的,那就来个投机取巧。先画一个方形的小块再接上圆角的。类似这样你懂的吧。
在这里插入图片描述

还有个绿点的绘制。这里我们要用到一个公式,已知圆心、半径、角度求圆上点的坐标
            float radius = pmProgressWidth / 2;
            float x = (float) (centerX + Math.cos(radian) * radius);
            float y = (float) (centerY + Math.sin(radian) * radius);
//arc角度大于3我们画 如果小于3直接画个绿点即可
if (arc >= 3) {
            paint.setStrokeCap(Paint.Cap.SQUARE);
            canvas.drawArc(rect, 93, 1, false, paint);
            paint.setStrokeCap(Paint.Cap.ROUND);
            canvas.drawArc(rect, 94, arc, false, paint);
            float radian = (float) Math.toRadians(arc + 93);
            float centerX = rect.centerX();
            float centerY = rect.centerY();
            float radius = pmProgressWidth / 2;
            float x = (float) (centerX + Math.cos(radian) * radius);
            float y = (float) (centerY + Math.sin(radian) * radius);
            paint.setColor(Color.RED);
            RectF rectDot = new RectF(x - pmPaintWidth / 2, y - pmPaintWidth / 2, x + pmPaintWidth / 2, y + pmPaintWidth / 2);
            //绘制甲醛图片背景
            canvas.drawBitmap(dotImg, null, rectDot, null);
        } else {
            //绘制甲醛图片背景
            canvas.drawBitmap(dotImg, rect.centerX() - pmPaintWidth / 2, rect.bottom - pmPaintWidth / 2, null);
        }
接下来画文字

这里借助Path这类,在路径上画文字

//绘制甲醛文字
        Path path = new Path();
        path.moveTo(mMeasureWidth / 2 + 15, rect.bottom + 10);//移动到圆形下方
        path.lineTo(mMeasureWidth, rect.bottom);//水平的路径
        textPaint.setTextSize(AutoSizeUtils.dp2px(getContext(), 14));
        canvas.drawTextOnPath(gasData.getGasName(), path, 0, 0, textPaint);//画文字
大功告成,最后贴上完整代码。你等的不就是这么。。

GasView.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.iisfree.smarthome.R;
import com.iisfree.smarthome.model.bean.DeviceBean;
import java.util.ArrayList;
import java.util.List;
import me.jessyan.autosize.utils.AutoSizeUtils;
public class GasView extends View {
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
    private Paint textPaint;
    private List gasDataList;
    private int mMeasureHeight;
    private int mMeasureWidth;
    private float whitePaintWidth;//白色圆弧宽度
    private float grayPaintWidth;//灰色圆弧宽度
    private float pmPaintWidth;//红色圆点宽度
    private float bgWidth;//背景图大小
    private float bgProgressWidth;//进度图大小
    private Bitmap imgBg;
    private Bitmap imgProgressBg;
    private Bitmap dotImg;
    private float[] whiteCircle;
    private float pmProgressWidth;//彩色进度条的半径
    public GasView(Context context) {
        super(context);
        initPaint(context);
    }
    public GasView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint(context);
    }
    public GasView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint(context);
    }
    private void initPaint(Context context) {
        gasDataList = new ArrayList();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.WHITE);
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(AutoSizeUtils.dp2px(getContext(), 8));
        textPaint.setColor(Color.parseColor("#666666"));
        textPaint.setStyle(Paint.Style.FILL);
        whitePaintWidth = AutoSizeUtils.dp2px(getContext(), 2);//白色圆弧宽度
        grayPaintWidth = AutoSizeUtils.dp2px(getContext(), 1);//灰色圆弧宽度
        pmPaintWidth = AutoSizeUtils.dp2px(getContext(), 13);//红色圆点宽度
        bgWidth = AutoSizeUtils.dp2px(getContext(), 136);//红色圆点宽度
        bgProgressWidth = AutoSizeUtils.dp2px(getContext(), 168);//红色圆点宽度
        pmProgressWidth = AutoSizeUtils.dp2px(getContext(), 157);
        whiteCircle = new float[]{AutoSizeUtils.dp2px(getContext(), 192),
                AutoSizeUtils.dp2px(getContext(), 208),
                AutoSizeUtils.dp2px(getContext(), 226), AutoSizeUtils.dp2px(getContext(), 244)};
        //绘制背景图片
        BitmapFactory.Options option = new BitmapFactory.Options();
        option.inScaled = false;
        option.inPreferredConfig = Bitmap.Config.ARGB_8888;
        imgBg = BitmapFactory.decodeResource(getResources(), R.mipmap.air_img_03, option).copy(Bitmap.Config.ARGB_8888, true);
        imgProgressBg = BitmapFactory.decodeResource(getResources(), R.mipmap.air_img_02, option).copy(Bitmap.Config.ARGB_8888, true);
        dotImg = BitmapFactory.decodeResource(getResources(), R.mipmap.air_img_01, option).copy(Bitmap.Config.ARGB_8888, true);
    }
    public void freshData(List gasDataList) {
        this.gasDataList.clear();
        this.gasDataList.addAll(gasDataList);
        postInvalidate();
    }
    private static final String TAG = "GasView";
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (this.gasDataList == null || this.gasDataList.size() == 0) return;
        paint.setStrokeCap(Paint.Cap.BUTT);
        RectF rectF = new RectF(mMeasureWidth / 2 - bgWidth / 2,
                mMeasureHeight / 2 - bgWidth / 2,
                mMeasureWidth / 2 + bgWidth / 2,
                mMeasureHeight / 2 + bgWidth / 2);
        //绘制背景图片
        canvas.drawBitmap(imgBg, null, rectF, null);
        RectF recBg = new RectF(mMeasureWidth / 2 - bgProgressWidth / 2,
                mMeasureHeight / 2 - bgProgressWidth / 2,
                mMeasureWidth / 2 + bgProgressWidth / 2,
                mMeasureHeight / 2 + bgProgressWidth / 2);
        //绘制甲醛图片背景
        canvas.drawBitmap(imgProgressBg, null, recBg, null);
        for (GasData gasData : gasDataList) {
            float progressR = 0;
            switch (gasData.getSensorType()) {
                case 0: {
                    drawCh2o(canvas, gasData);
                }
                break;
                case 1: {
                    progressR = whiteCircle[0];
                }
                break;
                case 2: {
                    progressR = whiteCircle[1];
                }
                break;
                case 3: {
                    progressR = whiteCircle[2];
                }
                break;
                case 4: {
                    progressR = whiteCircle[3];
                }
                break;
            }
            if (gasData.getSensorType() != 0) {
                RectF rect = new RectF(mMeasureWidth / 2 - progressR / 2,
                        mMeasureHeight / 2 - progressR / 2,
                        mMeasureWidth / 2 + progressR / 2,
                        mMeasureHeight / 2 + progressR / 2);
                //绘制灰色圆
                paint.setColor(Color.parseColor("#958280"));
                paint.setStrokeWidth(grayPaintWidth);
                canvas.drawArc(rect, 90, 270, false, paint);
                //绘制白色圆
                paint.setColor(Color.WHITE);
                paint.setStrokeWidth(whitePaintWidth);
                float arc = 270 * gasData.getProgress() / gasData.getMax();
                if(arc>270) arc = 270;
                paint.setColor(Color.WHITE);
                paint.setStrokeWidth(4);
                canvas.drawArc(rect, 90, arc, false, paint);
                Path path = new Path();
                path.moveTo(mMeasureWidth / 2 + 20, rect.bottom + 5);
                path.lineTo(mMeasureWidth, rect.bottom);
                textPaint.setTextSize(AutoSizeUtils.dp2px(getContext(), 8));
                canvas.drawTextOnPath(gasData.getGasName(), path, 0, 0, textPaint);
            }
        }
    }
    private void drawCh2o(Canvas canvas, GasData gasData) {
        //绘制甲醛
        float arc = 270 * gasData.getProgress() / gasData.getMax();
        if(arc>270) arc = 270;
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(pmPaintWidth);
        RectF rect = new RectF(mMeasureWidth / 2 - pmProgressWidth / 2,
                mMeasureHeight / 2 - pmProgressWidth / 2,
                mMeasureWidth / 2 + pmProgressWidth / 2,
                mMeasureHeight / 2 + pmProgressWidth / 2);
        Log.d(TAG, "onDraw角度: " + arc);
        if (arc >= 3) {
            paint.setStrokeCap(Paint.Cap.SQUARE);
            canvas.drawArc(rect, 93, 1, false, paint);
            paint.setStrokeCap(Paint.Cap.ROUND);
            canvas.drawArc(rect, 94, arc, false, paint);
            float radian = (float) Math.toRadians(arc + 93);
            float centerX = rect.centerX();
            float centerY = rect.centerY();
            float radius = pmProgressWidth / 2;
            float x = (float) (centerX + Math.cos(radian) * radius);
            float y = (float) (centerY + Math.sin(radian) * radius);
            paint.setColor(Color.RED);
            RectF rectDot = new RectF(x - pmPaintWidth / 2, y - pmPaintWidth / 2, x + pmPaintWidth / 2, y + pmPaintWidth / 2);
            //绘制甲醛图片背景
            canvas.drawBitmap(dotImg, null, rectDot, null);
        } else {
            //绘制甲醛图片背景
            canvas.drawBitmap(dotImg, rect.centerX() - pmPaintWidth / 2, rect.bottom - pmPaintWidth / 2, null);
        }
        //绘制甲醛文字
        Path path = new Path();
        path.moveTo(mMeasureWidth / 2 + 15, rect.bottom + 10);
        path.lineTo(mMeasureWidth, rect.bottom);
        textPaint.setTextSize(AutoSizeUtils.dp2px(getContext(), 14));
        canvas.drawTextOnPath(gasData.getGasName(), path, 0, 0, textPaint);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mMeasureWidth = getMeasuredWidth();
        mMeasureHeight = getMeasuredHeight();
    }
}

GasData.java
自己的数据实体实现这个接口即可

public interface GasData {
    String getGasName();//气体名字
    int getMax();//气体最大值
    int getProgress();//当前气体浓度
    int getSensorType();//气体类型
}

有什么不懂得联系我 QQ910689331


作者:Liberation_kkk


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯