Android进阶之路 - 静态会员进度条

server/2024/9/23 0:09:46/

年后这个新版本加入了VIP模块,有幸正好由我来负责,可以再积累一下这方面的知识。

那段时间看了一本书,书中说到初级码农的特性之一就是完全集中于某些功能,忽略了了很多成长机会,所以重复性劳作带来的成长值有限,大家应该去接触更广、更深的内容

进度条Blog

静态进度条一般只用于实现显示效果,无其他任何交互行为
在这里插入图片描述

年过半许

    • 基础概要
      • 功能分析
      • 组件解析
    • 开发实践
    • 项目场景
      • 圆角尺寸与设计图不符?
      • 设置对应进度值后,显示异常?

基础概要

起初想着自己写一下自定义控件就行,但是通过查询相关控件后发现自己考虑还是有限,所以直接借鉴了早期前辈写的控件,毕竟考虑比我当前全面,功能扩展也多一些

功能分析

在这里插入图片描述

要实现类似进度条,起码有以下几点要考虑到

  • 需绘制双进度条:一条 width 默认为控件宽度,用于背景效果;一条 width 需进行计算,实时显示当前进度
  • 进度条计算:计算的规则至少需要当前进度值最大值,否则无法进行基础计算
  • 进度条配置不同:对应 Paint 画笔,除大部分配置相同外,颜色至少要不同
  • padding考虑:有些控件为了显示效果更佳,会加入padding设置,这时候计算widthheight时要考虑到padding尺寸

通过以上简单分析,我们可以分析出我们需要的一些基本自定义属性,例如

组件解析

看了不少进度条控件,最后还是选了 ZzHorizontalProgressBar (始于2016,2021有过改动),虽然并不是多么出名,但自己用的舒服就好,下面简单介绍一下我对这款控件的理解

作用范围

  • 支持 静态设置、动态设置
  • 支持 三种显示模式,矩形,圆角形等
  • 支持 自定义圆角大小
  • 支持 渐变色
  • 支持 双进度条
  • 支持 成长值回调
  • 支持 设置进度条边框、边框色

属性说明

在这里插入图片描述

有兴趣的主要看这部分方法的实现就好,对应的分别是绘制进度条背景、绘制当前进度条、绘制边框

在这里插入图片描述

以矩形为例,一起看看 绘制进度条背景、绘制当前进度条

绘制进度条背景实现简单,可以简单了解

在这里插入图片描述

绘制当前进度条除了公共部分,可以直接看else部分(如果有渐变需求的可以看看 if 部分)

在这里插入图片描述


开发实践

为表尊重,保持作者原始注释、命名等

为了减少外部引用带来的影响,我将 ZzHorizontalProgressBar 的核心部分 copy 了出来 ,主要有自定义属性+自定义控件,为了方便 Demo 效果采用了静态设置方式,建议自行根据开发场景选择对应方式(在实际项目中我通过 静态+动态 的方式来实现效果)

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="ZzHorizontalProgressBar"><attr name="zpb_padding" format="dimension" /><attr name="zpb_bg_color" format="color|reference" /><attr name="zpb_pb_color" format="color|reference" /><attr name="zpb_second_pb_color" format="color|reference" /><attr name="zpb_max" format="integer" /><attr name="zpb_progress" format="integer" /><attr name="zpb_show_zero_point" format="boolean" /><attr name="zpb_show_second_progress" format="boolean" /><attr name="zpb_second_progress" format="integer" /><attr name="zpb_show_second_point_shape" format="enum"><enum name="point" value="0"/><enum name="line" value="1"/></attr><attr name="zpb_open_gradient" format="boolean" /><attr name="zpb_gradient_from" format="color|reference" /><attr name="zpb_gradient_to" format="color|reference" /><attr name="zpb_open_second_gradient" format="boolean" /><attr name="zpb_second_gradient_from" format="color|reference" /><attr name="zpb_second_gradient_to" format="color|reference" /><attr name="zpb_show_mode" format="enum" ><enum name="round" value="0"/><enum name="rect" value="1"/><enum name="round_rect" value="2"/></attr><attr name="zpb_round_rect_radius" format="dimension|reference"/><attr name="zpb_draw_border" format="boolean"/><attr name="zpb_border_width" format="dimension|reference"/><attr name="zpb_border_color" format="color|reference"/></declare-styleable>
</resources>

自定义控件

Tip:因类内有小千行代码,建议使用者直接copy该类

package com.example.lineprogress;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 水平进度条** Created by 周卓 on 2016/9/22.*/
public class ZzHorizontalProgressBar extends View {public static final int SHOW_MODE_ROUND = 0;public static final int SHOW_MODE_RECT = 1;public static final int SHOW_MODE_ROUND_RECT = 2;public static final int SHAPE_POINT = 0;public static final int SHAPE_LINE = 1;private int mMax;private int mProgress;private int mBgColor;private int mProgressColor;private int mPadding;private boolean mOpenGradient;private int mGradientFrom;private int mGradientTo;private boolean mShowSecondProgress;private int mSecondProgress;private int mSecondProgressShape;private boolean mShowZeroPoint;private Paint mSecondProgressPaint;private Paint mSecondGradientPaint;private Paint mProgressPaint;private Paint mGradientPaint;private Paint mBgPaint;private boolean mOpenSecondGradient;private int mSecondGradientFrom;private int mSecondGradientTo;private int mSecondProgressColor;private int mRadius;private boolean mDrawBorder = false;private int mBorderColor;private int mBorderWidth;private int mShowMode = 0;private Paint mBorderPaint;@IntDef({SHOW_MODE_ROUND, SHOW_MODE_RECT, SHOW_MODE_ROUND_RECT})@Target({ElementType.PARAMETER, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)private @interface ShowMode {}@IntDef({SHAPE_POINT, SHAPE_LINE})@Target({ElementType.PARAMETER, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)private @interface SecondProgressShape {}private OnProgressChangedListener mOnProgressChangedListener;public interface OnProgressChangedListener {void onProgressChanged(ZzHorizontalProgressBar progressBar, int max, int progress);void onSecondProgressChanged(ZzHorizontalProgressBar progressBar, int max, int progress);}public ZzHorizontalProgressBar(Context context) {super(context);init(context, null);}public ZzHorizontalProgressBar(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs);}public ZzHorizontalProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {initAttrs(context, attrs);initPaths();}private void initAttrs(Context context, AttributeSet attrs) {TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ZzHorizontalProgressBar);mMax = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_max, 100);mProgress = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_progress, 0);mBgColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_bg_color, 0xff3F51B5);mProgressColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_pb_color, 0xffFF4081);mSecondProgressColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_pb_color, 0xffFF4081);mPadding = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_padding, 0);mShowZeroPoint = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_show_zero_point, false);mShowSecondProgress = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_show_second_progress, false);mSecondProgress = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_second_progress, 0);mSecondProgressShape = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_show_second_point_shape, SHAPE_POINT);mOpenGradient = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_open_gradient, false);mGradientFrom = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_gradient_from, 0xffFF4081);mGradientTo = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_gradient_to, 0xffFF4081);mOpenSecondGradient = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_open_second_gradient, false);mShowMode = a.getInt(R.styleable.ZzHorizontalProgressBar_zpb_show_mode, SHOW_MODE_ROUND);mSecondGradientFrom = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_gradient_from, 0xffFF4081);mSecondGradientTo = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_gradient_to, 0xffFF4081);mRadius = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_round_rect_radius, 20);mDrawBorder = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_draw_border, false);mBorderWidth = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_border_width, 1);mBorderColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_border_color, 0xffff001f);a.recycle();}private void initPaths() {//常规进度条效果mProgressPaint = new Paint();mProgressPaint.setColor(mProgressColor);mProgressPaint.setStyle(Paint.Style.FILL);mProgressPaint.setAntiAlias(true);mSecondProgressPaint = new Paint();mSecondProgressPaint.setColor(mSecondProgressColor);mSecondProgressPaint.setStyle(Paint.Style.FILL);mSecondProgressPaint.setAntiAlias(true);//渐变效果mGradientPaint = new Paint();mGradientPaint.setStyle(Paint.Style.FILL);mGradientPaint.setAntiAlias(true);mSecondGradientPaint = new Paint();mSecondGradientPaint.setStyle(Paint.Style.FILL);mSecondGradientPaint.setAntiAlias(true);//背景效果mBgPaint = new Paint();mBgPaint.setColor(mBgColor);mBgPaint.setStyle(Paint.Style.FILL);mBgPaint.setAntiAlias(true);mBorderPaint = new Paint();mBorderPaint.setColor(mBorderColor);mBorderPaint.setStyle(Paint.Style.STROKE);mBorderPaint.setStrokeWidth(mBorderWidth);mBorderPaint.setAntiAlias(true);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);switch (mShowMode) {case SHOW_MODE_ROUND://half circledrawBackgroundCircleMode(canvas);drawProgressCircleMode(canvas);drawBorderCircleMode(canvas);break;case SHOW_MODE_RECT://rectdrawBackgroundRectMode(canvas);drawProgressRectMode(canvas);drawBorderRectMode(canvas);break;case SHOW_MODE_ROUND_RECT://custom radiusdrawBackgroundRoundRectMode(canvas);drawProgressRoundRectMode(canvas);drawBorderRoundRect(canvas);break;}}/*** 绘制半圆形进度*/private void drawProgressCircleMode(Canvas canvas) {int width = getWidth();float percent = 0;if (mMax != 0) {percent = mProgress * 1.0f / mMax;}int progressHeight = getHeight() - mPadding * 2;if (mOpenGradient) {int progressWidth = width - mPadding * 2;float dx = progressWidth * percent;int[] colors = new int[2];float[] positions = new float[2];//from colorcolors[0] = mGradientFrom;positions[0] = 0;//to colorcolors[1] = mGradientTo;positions[1] = 1;LinearGradient shader = new LinearGradient(mPadding + progressHeight / 2.0f, mPadding, mPadding + progressHeight / 2.0f + dx, mPadding + progressHeight,colors,positions,Shader.TileMode.MIRROR);//gradientmGradientPaint.setShader(shader);int radius = width > getHeight() ? getHeight() / 2 : width / 2;if (dx < getHeight()) {//left circleif (mProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(mPadding + progressHeight / 2.0f, mPadding + progressHeight / 2.0f, progressHeight / 2.0f, mGradientPaint);}} else {canvas.drawCircle(mPadding + progressHeight / 2.0f, mPadding + progressHeight / 2.0f, progressHeight / 2.0f, mGradientPaint);}} else {//progress lineRectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + progressHeight);canvas.drawRoundRect(rectF, radius, radius, mGradientPaint);}} else {int progressWidth = width - mPadding * 2 - progressHeight;float dx = progressWidth * percent;mProgressPaint.setColor(mProgressColor);float left = mPadding + progressHeight / 2.0f;//left circleif (mProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(left, left, progressHeight / 2.0f, mProgressPaint);}} else {canvas.drawCircle(left, left, progressHeight / 2.0f, mProgressPaint);}//right circleif (mProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(left + dx, left, progressHeight / 2.0f, mProgressPaint);}} else {canvas.drawCircle(left + dx, left, progressHeight / 2.0f, mProgressPaint);}//middle lineRectF rectF = new RectF(left, mPadding, left + dx, mPadding + progressHeight);canvas.drawRect(rectF, mProgressPaint);}//draw second progressif (mShowSecondProgress) {float secondPercent = 0;if (mMax != 0) {secondPercent = mSecondProgress * 1.0f / mMax;}int secondProgressHeight = getHeight() - mPadding * 2;if (mOpenSecondGradient) {int secondProgressWidth = width - mPadding * 2;float secondDx = secondProgressWidth * secondPercent;int[] secondColors = new int[2];float[] secondPositions = new float[2];//from colorsecondColors[0] = mSecondGradientFrom;secondPositions[0] = 0;//to colorsecondColors[1] = mSecondGradientTo;secondPositions[1] = 1;LinearGradient secondShader = new LinearGradient(mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + secondDx, mPadding + secondProgressHeight,secondColors,secondPositions,Shader.TileMode.MIRROR);//gradientmSecondGradientPaint.setShader(secondShader);int secondRadius = width > getHeight() ? getHeight() / 2 : width / 2;if (secondDx < getHeight()) {//left circleif (mSecondProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondGradientPaint);}} else {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondGradientPaint);}} else {//progress lineRectF rectF = new RectF(mPadding, mPadding, mPadding + secondDx, mPadding + secondProgressHeight);canvas.drawRoundRect(rectF, secondRadius, secondRadius, mSecondGradientPaint);}} else {//no gradientif (mSecondProgressShape == 0) {//point shapeint secondProgressWidth = width - mPadding * 2;float secondDx = secondProgressWidth * secondPercent;//progress linefloat px = mPadding + secondProgressHeight / 2.0f + secondDx;if (px < width - mPadding - secondProgressHeight / 2.0f) {if (mSecondProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(px, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}} else {canvas.drawCircle(px, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}} else {canvas.drawCircle(px - secondProgressHeight, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}} else {//line shapeint secondProgressWidth = width - mPadding * 2 - secondProgressHeight;float dx = secondProgressWidth * secondPercent;mSecondProgressPaint.setColor(mSecondProgressColor);//left circleif (mSecondProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}} else {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}//right circleif (mSecondProgress == 0) {if (mShowZeroPoint) {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}} else {canvas.drawCircle(mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);}//middle lineRectF rectF = new RectF(mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight);canvas.drawRect(rectF, mSecondProgressPaint);}}}}/*** 绘制方形进度*/private void drawProgressRectMode(Canvas canvas) {int width = getWidth();float percent = 0;if (mMax != 0) {percent = mProgress * 1.0f / mMax;}int progressHeight = getHeight() - mPadding * 2;if (mOpenGradient) {int progressWidth = width - mPadding * 2;float mDx = progressWidth * percent;int[] colors = new int[2];float[] positions = new float[2];//from colorcolors[0] = mGradientFrom;positions[0] = 0;//to colorcolors[1] = mGradientTo;positions[1] = 1;LinearGradient shader = new LinearGradient(mPadding + progressHeight / 2.0f, mPadding, mPadding + progressHeight / 2.0f + mDx, mPadding + progressHeight,colors,positions,Shader.TileMode.MIRROR);//gradientmGradientPaint.setShader(shader);//progress lineRectF rectF = new RectF(mPadding, mPadding, mPadding + mDx, mPadding + progressHeight);canvas.drawRect(rectF, mGradientPaint);} else {int progressWidth = width - mPadding * 2;float dx = progressWidth * percent;mProgressPaint.setColor(mProgressColor);RectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + progressHeight);canvas.drawRect(rectF, mProgressPaint);}//draw second progressif (mShowSecondProgress) {float secondPercent = 0;if (mMax != 0) {secondPercent = mSecondProgress * 1.0f / mMax;}int secondProgressHeight = getHeight() - mPadding * 2;if (mOpenSecondGradient) {int secondProgressWidth = width - mPadding * 2;float secondDx = secondProgressWidth * secondPercent;int[] secondColors = new int[2];float[] secondPositions = new float[2];//from colorsecondColors[0] = mSecondGradientFrom;secondPositions[0] = 0;//to colorsecondColors[1] = mSecondGradientTo;secondPositions[1] = 1;LinearGradient secondShader = new LinearGradient(mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + secondDx, mPadding + secondProgressHeight,secondColors,secondPositions,Shader.TileMode.MIRROR);//gradientmSecondGradientPaint.setShader(secondShader);//progress lineRectF rectF = new RectF(mPadding, mPadding, mPadding + secondDx, mPadding + secondProgressHeight);canvas.drawRect(rectF, mSecondGradientPaint);} else {//no gradient//line shapeint secondProgressWidth = width - mPadding * 2;float dx = secondProgressWidth * secondPercent;mSecondProgressPaint.setColor(mSecondProgressColor);RectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + secondProgressHeight);canvas.drawRect(rectF, mSecondProgressPaint);}}}/*** 绘制圆角矩形进度*/private void drawProgressRoundRectMode(Canvas canvas) {int width = getWidth();float percent = 0;if (mMax != 0) {percent = mProgress * 1.0f / mMax;}int progressHeight = getHeight() - mPadding * 2;int progressWidth = width - mPadding * 2 - mBorderWidth;float dx = progressWidth * percent;if (mOpenGradient) {int[] colors = new int[2];float[] positions = new float[2];//from colorcolors[0] = mGradientFrom;positions[0] = 0;//to colorcolors[1] = mGradientTo;positions[1] = 1;float left = mPadding + progressHeight / 2.0f;LinearGradient shader = new LinearGradient(left, mPadding, left + dx, mPadding + progressHeight,colors,positions,Shader.TileMode.MIRROR);//gradientmGradientPaint.setShader(shader);//progress linefloat rectLeft = mPadding + mBorderWidth / 2.0f;float rectTop = mPadding + mBorderWidth / 2.0f;RectF rectF = new RectF(rectLeft, rectTop, rectLeft + dx, getHeight() - rectTop);canvas.drawRoundRect(rectF, mRadius, mRadius, mGradientPaint);} else {mProgressPaint.setColor(mProgressColor);float rectLeft = mPadding + mBorderWidth / 2.0f;float rectTop = mPadding + mBorderWidth / 2.0f;RectF rectF = new RectF(rectLeft, rectTop, rectLeft + dx, getHeight() - rectTop);canvas.drawRoundRect(rectF, mRadius, mRadius, mProgressPaint);}//draw second progressif (mShowSecondProgress) {float secondPercent = 0;if (mMax != 0) {secondPercent = mSecondProgress * 1.0f / mMax;}int secondProgressHeight = getHeight() - mPadding * 2;int secondProgressWidth = width - mPadding * 2 - mBorderWidth;float secondDx = secondProgressWidth * secondPercent;if (mOpenSecondGradient) {int[] secondColors = new int[2];float[] secondPositions = new float[2];//from colorsecondColors[0] = mSecondGradientFrom;secondPositions[0] = 0;//to colorsecondColors[1] = mSecondGradientTo;secondPositions[1] = 1;float left = mPadding + secondProgressHeight / 2.0f;LinearGradient secondShader = new LinearGradient(left, mPadding, left + secondDx, mPadding + secondProgressHeight,secondColors,secondPositions,Shader.TileMode.MIRROR);//gradientmSecondGradientPaint.setShader(secondShader);//progress linefloat rectLeft = mPadding + mBorderWidth / 2.0f;float rectTop = mPadding + mBorderWidth / 2.0f;RectF rectF = new RectF(rectLeft, rectTop, rectLeft + secondDx, getHeight() - rectTop);canvas.drawRoundRect(rectF, mRadius, mRadius, mSecondGradientPaint);} else {//no gradient//line shapemSecondProgressPaint.setColor(mSecondProgressColor);float rectLeft = mPadding + mBorderWidth / 2.0f;float rectTop = mPadding + mBorderWidth / 2.0f;RectF rectF = new RectF(rectLeft, rectTop, rectLeft + secondDx, getHeight() - rectTop);canvas.drawRoundRect(rectF, mRadius, mRadius, mSecondProgressPaint);}}}/*** 绘制半圆形背景*/private void drawBackgroundCircleMode(Canvas canvas) {int bgHeight = getHeight();int width = getWidth();//left circlecanvas.drawCircle(bgHeight / 2.0f, bgHeight / 2.0f, bgHeight / 2.0f, mBgPaint);//right circlecanvas.drawCircle(width - bgHeight / 2.0f, bgHeight / 2.0f, bgHeight / 2.0f, mBgPaint);//middle lineRectF rectF = new RectF(bgHeight / 2.0f, 0, width - bgHeight / 2.0f, bgHeight);canvas.drawRect(rectF, mBgPaint);}/*** 绘制半圆形边框*/private void drawBorderCircleMode(Canvas canvas) {if (mDrawBorder) {int bgHeight = getHeight();int width = getWidth();RectF rect = new RectF(0, 0, width, bgHeight);canvas.drawRoundRect(rect, bgHeight / 2.0f, bgHeight / 2.0f, mBorderPaint);}}/*** 绘制半方形边框*/private void drawBorderRectMode(Canvas canvas) {if (mDrawBorder) {int bgHeight = getHeight();int width = getWidth();RectF rect = new RectF(0, 0, width, bgHeight);canvas.drawRect(rect, mBorderPaint);}}/*** 绘制圆角矩形边框*/private void drawBorderRoundRect(Canvas canvas) {if (mDrawBorder) {int bgHeight = getHeight();int width = getWidth();RectF rect = new RectF(mBorderWidth / 2.0f, mBorderWidth / 2.0f, width - mBorderWidth / 2.0f, bgHeight - mBorderWidth / 2.0f);canvas.drawRoundRect(rect, mRadius, mRadius, mBorderPaint);}}/*** 绘制方形背景*/private void drawBackgroundRectMode(Canvas canvas) {int bgHeight = getHeight();int width = getWidth();RectF rectF = new RectF(0, 0, width, bgHeight);canvas.drawRect(rectF, mBgPaint);}/*** 绘制圆角矩形背景*/private void drawBackgroundRoundRectMode(Canvas canvas) {int bgHeight = getHeight();int width = getWidth();RectF rectF = new RectF(mBorderWidth / 2.0f, mBorderWidth / 2.0f, width - mBorderWidth / 2.0f, bgHeight - mBorderWidth / 2.0f);canvas.drawRoundRect(rectF, mRadius, mRadius, mBgPaint);}/*** 获取最大值** @return 最大值*/public int getMax() {return mMax;}/*** 设置最大值** @param max 最大值*/public void setMax(int max) {this.mMax = max;invalidate();}/*** 获取一级进度值** @return 进度值*/public int getProgress() {return mProgress;}/*** 设置一级进度值** @param progress 进度值*/public void setProgress(int progress) {if (progress < 0) {this.mProgress = 0;} else if (progress > mMax) {this.mProgress = mMax;} else {this.mProgress = progress;}invalidate();if (mOnProgressChangedListener != null) {mOnProgressChangedListener.onProgressChanged(this, mMax, this.mProgress);}}/*** 是否显示二级进度条** @return 是/否*/public boolean isShowSecondProgress() {return mShowSecondProgress;}/*** 设置是否显示二级进度条** @param showSecondProgress 是/否*/public void setShowSecondProgress(boolean showSecondProgress) {this.mShowSecondProgress = showSecondProgress;invalidate();}/*** 获取二级进度条进度** @return 进度值*/public int getSecondProgress() {return mSecondProgress;}/*** 设置二级进度条进度** @param secondProgress 进度值*/public void setSecondProgress(int secondProgress) {if (secondProgress < 0) {this.mSecondProgress = 0;} else if (secondProgress > mMax) {this.mSecondProgress = mMax;} else {this.mSecondProgress = secondProgress;}invalidate();if (mOnProgressChangedListener != null) {mOnProgressChangedListener.onSecondProgressChanged(this, mMax, this.mSecondProgress);}}/*** 获取二级进度条形状** @return 形状,点:{@link #SHAPE_POINT} 线:{@link #SHAPE_LINE}*/public int getSecondProgressShape() {return mSecondProgressShape;}/*** 设置二级进度条形状** @param secondProgressShape 形状,点:{@link #SHAPE_POINT} 线:{@link #SHAPE_LINE}*/public void setSecondProgressShape(@SecondProgressShape int secondProgressShape) {this.mSecondProgressShape = secondProgressShape;invalidate();}/*** 获取背景色** @return 颜色值*/public int getBgColor() {return mBgColor;}/*** 设置背景色** @param bgColor 颜色值*/public void setBgColor(@ColorInt int bgColor) {this.mBgColor = bgColor;mBgPaint.setColor(bgColor);invalidate();}/*** 获取二级渐变是否启用** @return 是/否*/public boolean isOpenSecondGradient() {return mOpenSecondGradient;}/*** 设置二级渐变是否启用** @param openSecondGradient 是/否*/public void setOpenSecondGradient(boolean openSecondGradient) {this.mOpenSecondGradient = openSecondGradient;invalidate();}public int getSecondGradientFrom() {return mSecondGradientFrom;}public int getSecondGradientTo() {return mSecondGradientTo;}/*** 获取二级进度条颜色** @return 颜色值*/public int getSecondProgressColor() {return mSecondProgressColor;}/*** 设置二级进度条颜色** @param secondProgressColor 颜色值*/public void setSecondProgressColor(@ColorInt int secondProgressColor) {this.mSecondProgressColor = secondProgressColor;mSecondProgressPaint.setColor(secondProgressColor);invalidate();}/*** 获取一级进度条颜色** @return 颜色值*/public int getProgressColor() {return mProgressColor;}/*** 设置一级进度条颜色** @param progressColor 颜色值*/public void setProgressColor(@ColorInt int progressColor) {this.mProgressColor = progressColor;mProgressPaint.setColor(progressColor);invalidate();}/*** 获取内边距** @return 边距值*/public int getPadding() {return mPadding;}/*** 设置内边距** @param padding 边距值*/public void setPadding(int padding) {this.mPadding = padding;invalidate();}/*** 设置显示模式** @param showMode 显示模式,0:半圆,1:方形,2:圆角矩形*/public void setShowMode(@ShowMode int showMode) {switch (showMode) {case SHOW_MODE_ROUND:this.mShowMode = 0;break;case SHOW_MODE_RECT:this.mShowMode = 1;break;case SHOW_MODE_ROUND_RECT:this.mShowMode = 2;break;}invalidate();}/*** 获取进度百分比,int类型** @return percentage value*/public int getPercentage() {if (mMax == 0) {return 0;}return (int) (mProgress * 100.0f / mMax + 0.5f);}/*** 获取进度百分比,float类型** @return percentage value*/public float getPercentageFloat() {if (mMax == 0) {return 0f;}return mProgress * 100.0f / mMax;}/*** 一级渐变色是否启用** @return 是/否*/public boolean isOpenGradient() {return mOpenGradient;}/*** 设置一级渐变色是否启用** @param openGradient 是/否*/public void setOpenGradient(boolean openGradient) {this.mOpenGradient = openGradient;invalidate();}public int getGradientFrom() {return mGradientFrom;}public int getGradientTo() {return mGradientTo;}/*** 设置边框颜色** @param borderColor 颜色值*/public void setBorderColor(@ColorInt int borderColor) {this.mBorderColor = borderColor;this.mBorderPaint.setColor(this.mBorderColor);invalidate();}/*** 设置一级进度条的渐变色** @param from 起始颜色* @param to   结束颜色*/public void setGradientColor(int from, int to) {this.mGradientFrom = from;this.mGradientTo = to;invalidate();}/*** 设置二级进度条的渐变色** @param from 起始颜色* @param to   结束颜色*/public void setSecondGradientColor(int from, int to) {this.mSecondGradientFrom = from;this.mSecondGradientTo = to;invalidate();}/*** 设置一级进度条的渐变色和边框颜色** @param from        起始颜色* @param to          结束颜色* @param borderColor 边框颜色*/public void setGradientColorAndBorderColor(int from, int to, int borderColor) {this.mGradientFrom = from;this.mGradientTo = to;this.mBorderColor = borderColor;this.mBorderPaint.setColor(this.mBorderColor);invalidate();}/*** 获取边框颜色** @return 颜色值*/public int getBorderColor() {return mBorderColor;}/*** 设置进度变化监听(包括一级和二级进度)** @param onProgressChangedListener 进度值变化回调*/public void setOnProgressChangedListener(OnProgressChangedListener onProgressChangedListener) {this.mOnProgressChangedListener = onProgressChangedListener;}}

静态使用方式

如采用动态控件设置方式,则需要在对应组件内进行设置(因当前采用的是静态方式,可忽略MainActivity

package com.example.lineprogressimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundleclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}
}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><com.example.lineprogress.ZzHorizontalProgressBarandroid:layout_width="match_parent"android:layout_height="10dp"android:layout_marginHorizontal="30dp"android:layout_marginTop="20dp"app:zpb_bg_color="#7F683F"app:zpb_max="100"app:zpb_pb_color="#FFDFA8"app:zpb_progress="19"app:zpb_show_mode="round" /><com.example.lineprogress.ZzHorizontalProgressBarandroid:layout_width="match_parent"android:layout_height="10dp"android:layout_marginHorizontal="30dp"android:layout_marginTop="20dp"app:zpb_bg_color="#7F683F"app:zpb_max="100"app:zpb_pb_color="#FFDFA8"app:zpb_progress="19"app:zpb_show_mode="rect" /><com.example.lineprogress.ZzHorizontalProgressBarandroid:layout_width="match_parent"android:layout_height="10dp"android:layout_marginHorizontal="30dp"android:layout_marginTop="20dp"app:zpb_bg_color="#7F683F"app:zpb_max="100"app:zpb_pb_color="#FFDFA8"app:zpb_progress="19"app:zpb_show_mode="round_rect" /></androidx.appcompat.widget.LinearLayoutCompat>

项目场景

仅记录我在项目中使用该控件时所遇到的问题

圆角尺寸与设计图不符?

  1. 设置显示模式为 SHOW_MODE_ROUND_RECT
 progressLine.setShowMode(SHOW_MODE_ROUND_RECT)
  1. 通过静态方式在xml中设置app:zpb_round_rect_radius尺寸
 app:zpb_round_rect_radius="5dp"

设置对应进度值后,显示异常?

有可能显示为0,有可能显示满值,或者也有可能出现别的场景(到时候可以留言哈)

项目伪代码,接口数据一般采用 String 类型接收,为防止直接转换Int报错,可以先转Double再转Int

 progressLine.progress = floor(info?.growthValue?.toDouble() ?: 0.00).toInt()progressLine.max = floor(data?.nextGrowthValue?.toDouble() ?: 0.00).toInt()

http://www.ppmy.cn/server/40365.html

相关文章

docker(二):Centos安装docker

文章目录 1、安装docker2、启动docker3、验证 官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 1、安装docker 下载依赖包 yum -y install gcc yum -y install gcc-c yum install -y yum-utils设置仓库 yum-config-manager --add-repo http://mirrors…

Flink面试整理-如何提高Flink处理数据的效率和吞吐量

提高 Apache Flink 处理数据的效率和吞吐量通常涉及对配置、代码设计和资源管理的优化。以下是一些关键的策略: 1. 优化并行度 调整并行度:并行度应根据可用的硬件资源(如 CPU 核心数)进行调整。不同的算子可以有不同的并行度。确保数据均衡分配:避免某些任务过载而其他任…

Android studio 打开Device Mirroring方便调试

巧合下发现一个很好用的工具&#xff0c;在平时调试真机的时候在每次run app后都要低头找找手机看看效果。但是&#xff0c;用了AS上的Device Mirroring&#xff0c;你会发现根本不需要再低头点手机&#xff0c;调试方便一万倍啊。 话不多说&#xff0c;上图。直接就可以在电脑…

mysql中sql语句 exists 判断子句的用法

如果子查询成立才执行父查询 exists判断子查询的使用例子&#xff1a; 张三不存在所以前面的父查询不执行 后面的子句结果存在&#xff0c;所以前面的父查询被执行 where条件所连接的嵌套子查询都是&#xff0c;条件子查询 ———————————————————————…

最小生成树刷题笔记

算法基础&#xff1a; 最小生成树是所有节点的最小连通子图&#xff01;&#xff01;&#xff01;&#xff01; 首先是prim算法三部曲&#xff1a; &#xff08;1&#xff09;找到距离最小生成树最近的节点。 &#xff08;2&#xff09;将距离最小生成树最近的节点加入到最…

离线修复.dll,Microsoft Visual C++

在安装mysql时遇到下面的问题&#xff0c;如果是有网络的情况下微软管网下载安装就行了&#xff0c;用的服务器不允许连接互联网。 后面经过寻找&#xff0c;找到了一个修复工具&#xff0c;可一次修复所有的问题&#xff0c;特别好用分享给宝子们。 下载链接&#xff1a;http…

企业级复杂前中台项目响应式处理方案

目录 01: 前言 02: 响应式下navigtionBar实现方案分析 数据 视图 小结 03: 抽离公用逻辑&#xff0c;封装系列动作 04: PC端navigationBar私有逻辑处理 05: 分析 navigationBar 闪烁问题 06: 处理 navigationBar 闪烁问题 07: category数据缓存&#xff0c;覆盖…

机器学习案例:加州房产价格(二)

参考链接&#xff1a;https://hands1ml.apachecn.org/2/ 设计好系统后&#xff0c;要开始在工作区编写代码来解决问题了。 下载数据 首先我们需要先得到数据集。 一般情况下&#xff0c;数据是存储于关系型数据库&#xff08;或其它常见数据库&#xff09;中的多个表、文档、…