当前位置: 首页 > article >正文

Android 空气质量刻度

效果

在这里插入图片描述

attrs.xml
    <attr name="textSpace" format="dimension|reference" />
    <attr name="barSpace" format="dimension|reference" />
    <attr name="scaleHeight" format="dimension|reference" />
    <attr name="progressHeight" format="dimension|reference" />
    <attr name="barRadius" format="dimension|reference" />
    <attr name="barColor" format="color|reference" />
    <attr name="barOutColor" format="color|reference" />
    <attr name="textSize" format="dimension|reference" />
    <attr name="strokeColor" format="color|reference" />
    <attr name="strokeWidth" format="dimension|reference" />
    <attr name="max" format="integer|reference" />
    <attr name="progress" format="integer|reference" />
    <declare-styleable name="AirQualityBar">
        <attr name="textSpace" />
        <attr name="barSpace" />
        <attr name="scaleHeight" />
        <attr name="progressHeight" />
        <attr name="barRadius" />
        <attr name="barColor" />
        <attr name="barOutColor" />
        <attr name="textSize" />
        <attr name="strokeColor" />
        <attr name="strokeWidth" />
        <attr name="max" />
        <attr name="progress" />
    </declare-styleable>
使用
    //标签文字
    private String[] labels = new String[]{"优", "良", "轻度", "中度", "重度","严重"};
    //数据值
    private int[] values = new int[]{35, 75, 115, 150,250};
    //颜色
    private int[] colors = {
            Color.parseColor("#0BCB81"),
            Color.parseColor("#E0DE25"),
            Color.parseColor("#F9A13A"),
            Color.parseColor("#F93A3A"),
            Color.parseColor("#B61455"),
            Color.parseColor("#B61455"),
    };
        //颜色进度
    private float[] positions = {
            0f, 0.2f, 0.4f, 0.6f, 0.8f,1.0f
    };
    AirQualityBar bar = holder.find(R.id.air_quality_bar);
    bar.setGradient(colors , positions);
    bar.setLabels(labels );
    bar.setValues(values );
    bar.setMax(360);
    bar.setProgress(270, true);
源码
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import cn.anbao.forest.wards.R;


/**
 * 空气质量进度条
 */
public class AirQualityBar extends View implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {

    private Paint paint;
    //文字间隔
    private int textSpace = 10;
    //进度间隔
    private int barSpace = 4;
    //刻度高度
    private int scaleHeight = 4;
    //进度条高度
    private int progressHeight = 12;
    //圆点半径
    private int barRadius = 6;
    private int barColor = Color.WHITE;
    private int barOutColor = Color.parseColor("#80FFFFFF");
    //文字大小
    private int textSize = 14;
    //线条颜色
    private int strokeColor = Color.parseColor("#687785");
    //线条宽度
    private int strokeWidth = 2;
    //中间Y
    private int centerY;
    //View宽高
    private int width, height;
    //最大值
    private int max = 100;
    //进度值
    private int progress = 0;
    private int paintProgress;
    //标签文字
    private String[] labels = new String[]{"优", "良", "轻度", "中度", "重度","严重"};
    //数据值
    private int[] values = new int[]{35, 75, 115, 150,250};
    //颜色
    private int[] colors = {
            Color.parseColor("#0BCB81"),
            Color.parseColor("#E0DE25"),
            Color.parseColor("#F9A13A"),
            Color.parseColor("#F93A3A"),
            Color.parseColor("#B61455"),
            Color.parseColor("#B61455"),
    };
    private int[] paintColors;
    //颜色进度
    private float[] positions = {
            0f, 0.2f, 0.4f, 0.6f, 0.8f,1.0f
    };
    private float[] paintPositions;
    //进度圆角大小
    private int progressRadius;
    private ValueAnimator animator;

    public AirQualityBar(Context context) {
        this(context, null);
    }

    public AirQualityBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AirQualityBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public AirQualityBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initAttributeSet(context, attrs, defStyleAttr);
    }

    private void initAttributeSet(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        initAnimator();
        if (attrs != null) {
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AirQualityBar, defStyleAttr, 0);
            textSpace = array.getDimensionPixelOffset(R.styleable.AirQualityBar_textSpace, textSpace);
            barSpace = array.getDimensionPixelOffset(R.styleable.AirQualityBar_barSpace, barSpace);
            scaleHeight = array.getDimensionPixelOffset(R.styleable.AirQualityBar_scaleHeight, scaleHeight);
            progressHeight = array.getDimensionPixelOffset(R.styleable.AirQualityBar_progressHeight, progressHeight);
            barRadius = array.getDimensionPixelOffset(R.styleable.AirQualityBar_barRadius, barRadius);
            barColor = array.getColor(R.styleable.AirQualityBar_barColor, barColor);
            barOutColor = array.getColor(R.styleable.AirQualityBar_barOutColor, barOutColor);
            textSize = array.getDimensionPixelSize(R.styleable.AirQualityBar_textSize, textSize);
            strokeColor = array.getColor(R.styleable.AirQualityBar_strokeColor, strokeColor);
            strokeWidth = array.getDimensionPixelOffset(R.styleable.AirQualityBar_strokeWidth, strokeWidth);
            max = array.getInt(R.styleable.AirQualityBar_max, max);
            progress = array.getInt(R.styleable.AirQualityBar_progress, progress);
            array.recycle();
        }
        setProgress(progress);
        paintColors = colors;
        paintPositions = positions;
        paintProgress = progress;
    }

    private void initAnimator() {
        if (animator == null) {
            animator = new ValueAnimator();
            animator.setDuration(500);
            animator.addUpdateListener(this);
            animator.addListener(this);
        }
    }

    @Override
    public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
        paintProgress = (int) valueAnimator.getAnimatedValue();
        findSuitableColorsPositions(paintProgress);
        invalidate();
    }

    @Override
    public void onAnimationStart(@NonNull Animator animator) {

    }

    @Override
    public void onAnimationEnd(@NonNull Animator animator) {
        release();
    }

    @Override
    public void onAnimationCancel(@NonNull Animator animator) {

    }

    @Override
    public void onAnimationRepeat(@NonNull Animator animator) {

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        centerY = height / 2;
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(strokeWidth);
        paint.setTextSize(textSize);
        paint.setColor(strokeColor);
        //背景
        progressRadius = progressHeight / 2;
        RectF bounds = new RectF(0, centerY - progressRadius, width, centerY + progressRadius);
        canvas.drawRoundRect(bounds, progressRadius, progressRadius, paint);
        //进度
        float percent = getRealProgressValue(paintProgress) * 1.0F / max;
        paint.setStyle(Paint.Style.FILL);
        RectF rectF = new RectF(barSpace, centerY - progressRadius + barSpace, barSpace + (width - 2 * barSpace) * percent, centerY + progressRadius - barSpace);
        //线性渐变颜色
        if (paintColors.length > 1 && paintPositions.length > 1) {
            paint.setShader(new LinearGradient(rectF.left, rectF.top, rectF.right, rectF.top, paintColors, paintPositions, Shader.TileMode.CLAMP));
        } else {
            paint.setColor(paintColors[0]);
        }
        canvas.drawRoundRect(rectF, progressRadius, progressRadius, paint);
        //进度圆点
        if (percent > 0) {
            paint.setShader(null);
            int horizontal = width - 2 * barSpace;
            boolean isEnd = percent >= 0.95f;
            float cx = isEnd ? horizontal * percent - barSpace : horizontal * percent - barSpace/2;
            float cy = centerY;
            paint.setColor(barOutColor);
            canvas.drawCircle(cx + barSpace, cy, barRadius, paint);
            paint.setColor(barColor);
            float innerRadius = barRadius * 0.65f;
            canvas.drawCircle(cx + innerRadius, cy, innerRadius, paint);
        }
        //比例刻度
        drawScale(canvas, labels, values);
    }

    /**
     * 获取真实进度值
     *
     * @param progress
     * @return
     */
    private int getRealProgressValue(int progress) {
        return calculateProgress(values, max, progress);
    }

    /**
     * 计算进度
     *
     * @param values 数值数组
     * @param max    最大值
     * @param value  当前值
     * @return
     */
    private int calculateProgress(int[] values, int max, int value) {
        //重组新的数组
        int[] mixValues = Arrays.copyOf(values, values.length + 1);
        mixValues[mixValues.length - 1] = max;
        //每一段长度值
        int segmentValue = max / (mixValues.length);
        int progress = 0;
        for (int i = 0; i < mixValues.length; i++) {
            int preIndex = i - 1;
            int preValue = preIndex > -1 ? mixValues[preIndex] : 0;
            int itemValue = mixValues[i];
            if (value > preValue && value <= itemValue) {
                int diffValue = itemValue - preValue;
                int segmentProgress = (value - preValue) * segmentValue / diffValue;
                progress = (preIndex < 0 ? 0 : segmentValue * (preIndex + 1)) + segmentProgress;
            }
        }
        return progress;
    }

    /**
     * 获取进度百分比
     *
     * @return
     */
    public float getPercent() {
        return getRealProgressValue(progress) * 1.0F / max;
    }

    private List<Integer> colorList;
    private List<Float> positionList;

    /**
     * 找到合适的颜色和颜色位置
     */
    private void findSuitableColorsPositions(int progress) {
        float percent = progress * 1.0F / max;
        if (positions == null || colors == null) {
            return;
        }
        if (positions.length == 0 || colors.length == 0) {
            return;
        }
        if (colorList == null) {
            colorList = new ArrayList<>();
        } else {
            colorList.clear();
        }
        if (positionList == null) {
            positionList = new ArrayList<>();
        } else {
            positionList.clear();
        }
        for (int i = 0; i < positions.length; i++) {
            if (percent > positions[i]) {
                positionList.add(positions[i]);
                colorList.add(colors[i]);
            }
        }
        int colorSize = colorList.size();
        if (colorSize == 0) {
            return;
        }
        paintColors = new int[colorSize];
        for (int i = 0; i < colorList.size(); i++) {
            paintColors[i] = colorList.get(i);
        }
        int positionSize = positionList.size();
        if (positionSize == 0) {
            return;
        }
        paintPositions = new float[positionSize];
        float itemValue = 1.0F / positionSize;
        for (int i = 0; i < positionList.size(); i++) {
            paintPositions[i] = itemValue * (i + 1);
        }
    }

    /**
     * 绘制刻度比例
     *
     * @param canvas 画布
     * @param labels 标签
     * @param values 数值
     */
    private void drawScale(Canvas canvas, String[] labels, int[] values) {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(strokeColor);
        paint.setStrokeWidth(strokeWidth);
        paint.setTextSize(textSize);
        //上方
        int labelSize = labels.length;
        int labelItemWidth = width / labelSize;
        for (int i = 0; i < labelSize; i++) {
            //刻度
            float startX = labelItemWidth * (i + 1);
            float startY = centerY - progressRadius;
            float stopX = labelItemWidth * (i + 1);
            float stopY = startY - scaleHeight;
            if (i < labelSize - 1) {
                canvas.drawLine(startX, startY, stopX, stopY, paint);
            }
            //标签
            String label = labels[i];
            float x = startX - labelItemWidth / 2 - measureText(paint, label).width() / 2;
            float y = startY - textSpace;
            canvas.drawText(labels[i], x, y, paint);
        }
        //下方
        int valueCount = values.length;
        int valueItemWidth = width / labelSize;
        for (int i = 0; i < valueCount; i++) {
            //刻度
            float startX = valueItemWidth * (i + 1);
            float startY = centerY + progressRadius;
            float stopX = valueItemWidth * (i + 1);
            float stopY = startY + scaleHeight;
            canvas.drawLine(startX, startY, stopX, stopY, paint);
            //标签
            String value = values[i] + "";
            Rect bounds = measureText(paint, value);
            float x = startX - bounds.width() / 2;
            float y = stopY + textSpace + bounds.height() / 2;
            canvas.drawText(value, x, y, paint);
        }
    }

    /**
     * 测量Text
     *
     * @param paint
     * @param text
     * @return
     */
    private Rect measureText(Paint paint, String text) {
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        return bounds;
    }

    /**
     * 设置最大值
     *
     * @param max
     */
    public void setMax(int max) {
        this.max = max;
    }

    public int getProgress() {
        return progress;
    }

    /**
     * 设置进度
     *
     * @param progress 进度
     */
    public void setProgress(int progress) {
        setProgress(progress, true);
    }

    /**
     * 设置进度
     *
     * @param progress 进度
     * @param animator 是否动画
     */
    public void setProgress(int progress, boolean animator) {
        //数据没改变,不用刷新
        if (getProgress() == progress) {
            return;
        }
        progress = progress < 0 ? 0 : progress;
        if (progress == 0) {
            paintProgress = 0;
            findSuitableColorsPositions(paintProgress);
            invalidate();
            return;
        }
        this.progress = progress;
        if (animator) {
            startAnimator(progress);
        } else {
            paintProgress = progress;
            findSuitableColorsPositions(paintProgress);
            invalidate();
        }
    }

    /**
     * 开始动画
     *
     * @param value 值
     */
    private void startAnimator(int value) {
        initAnimator();
        animator.setIntValues(0, value);
        animator.start();
    }

    /**
     * 设置渐变
     *
     * @param colors    颜色
     * @param positions 位置
     */
    public void setGradient(int[] colors, float[] positions) {
        this.colors = colors;
        this.positions = positions;
        invalidate();
    }

    /**
     * 设置标签值
     *
     * @param labels
     */
    public void setLabels(String[] labels) {
        this.labels = labels;
        invalidate();
    }

    /**
     * 设置数值
     *
     * @param values
     */
    public void setValues(int[] values) {
        this.values = values;
        invalidate();
    }

    /**
     * 获取标签值
     *
     * @return
     */
    public String getLabel() {
        String label = "";
        float value = getPercent();
        int length = labels.length;
        for (int i = 0; i < length; i++) {
            float min = i * 1.F / length;
            float max = (i + 1) * 1.0F / length;
            if (value >= min && value < max) {
                label = labels[i];
            }
        }
        return label;
    }

    /**
     * 资源释放
     */
    public void release() {
        if (animator != null) {
            animator.cancel();
            animator.removeAllListeners();
            animator.removeAllUpdateListeners();
            animator = null;
        }
    }


}



http://www.kler.cn/news/313179.html

相关文章:

  • CleanClip For Mac 強大的剪貼簿助手Paste替代工具 v2.2.1
  • 学习笔记——EffcientNetV2
  • React——点击事件函数调用问题
  • Gradio离线部署到内网,资源加载失败问题(Gradio离线部署问题解决方法)
  • docker搭建个人网盘,支持多种格式,还能画图,一键部署
  • Matlab可视化│常用绘图全家桶
  • HTTP中的301、302实现重定向
  • ActivityManagerService 分发广播(6)
  • Vue3:reactive丢失响应式,数据有更新但表单没有更新
  • gin配置swagger文档
  • 树与图的深度优先遍历(dfs的图论中的应用)
  • 【CPP】类与继承
  • [原创]全新安装最新版Delphi 12.2之前, 如何正确卸载旧版Delphi 12.1?
  • 谈对象第二弹: C++类和对象(中)
  • SQLiteHelper
  • Java:List<String> 转换List<BigDecimal> 并求和
  • Hadoop-MapReduce的 原理 | 块和片 | Shuffle 过程 | Combiner
  • go 战略
  • Observability:构建下一代托管接入服务
  • Linux文件IO(四)-返回错误处理与errno详解
  • 【数据结构与算法】LeetCode:双指针法
  • 基于STM32F103C8T6单片机的DDS信号源设计
  • 海洋大地测量基准与水下导航系列之二国外海底大地测量基准和海底观测网络发展现状(上)
  • mac中git操作账号的删除
  • 【linux】4张卡,坏了1张,怎么办?
  • ActivityManagerService Activity的启动流程(2)
  • Windows10、CentOS Stream9 环境下安装kafka_2.12-3.6.2记录
  • Oracle数据库pl/sql显式抛出异常
  • Python 项目实践:文件批量处理
  • 软硬件项目运维方案(Doc原件完整版套用)