当前位置: 首页 > 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/a/313179.html

相关文章:

  • WLAN消失或者已连接但是访问不了互联网
  • 微服务各组件整合
  • apache2配置多站点
  • Llama架构及代码详解
  • Window下PHP安装最新sg11(php5.3-php8.3)
  • java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程
  • 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详解