Android实现绚丽的自定义进度条

目录
  • 前言
  • 效果图
  • 实现步骤
    • 1.绘制背景圆形矩形
    • 2.绘制进度
    • 3.绘制文字
    • 4.加入动画
  • 完整代码

前言

进度条是在Android项目中很常用的组件之一,如果想要理解它是怎么实现的,首先还需要了解自定义view和Android坐标系相关的知识,下面我来详细地介绍一下自定义进度条的实现过程。

本项目源码:https://gitee.com/tu_erhongjiang/android-progress-bar

效果图

实现步骤

1.绘制背景圆形矩形

首先要画出一个圆形矩形,RectF里面传递的是矩形左上角和右下角的xy坐标,这是用来确定矩形的位置和大小,然后在矩形内部画出一个圆形矩形。

核心代码:canvas.drawRoundRect()

private void drawBackground(Canvas canvas){
   //圆角矩形
    RectF rectF = new RectF(padding, padding, mWidth - padding, mHeight - padding);
    canvas.drawRoundRect(rectF, round, round, mPaintRoundRect);
}

2.绘制进度

其实里面的进度条也是圆形矩形,只不过进度条的画笔是实心的。内部进度条矩形的大小需要略小于外面的矩形,这样就可以实现上面的这种效果。如果进度条矩形大于或等于背景矩形大小的话那就完全压住背景中的边框,显示出来的只是一个没有边框的进度条,所以这里需要减掉strokeWidth。

private void drawProgress(Canvas canvas){
        if (process!=0){
            RectF rectProgress = new RectF(padding + strokeWidth, padding + strokeWidth, process, mHeight - padding - strokeWidth);//内部进度条
            canvas.drawRoundRect(rectProgress, round, round, mPaint);
        }
    }

3.绘制文字

下面来看看怎么居中文字:

getWidth() / 2 得到的结果是中间位置的x坐标,但是从这里开始绘制文字的话不能实现居中的效果。所以还需要计算出文字的长度,然后把文字整体左移。mTxtWidth / 2 是文字的中心位置,也就是说文字的中心位置移到矩形的中心位置就可以实现居中的效果。

    private void updateText(Canvas canvas) {
        String finishedText = getResources().getString(R.string.finished);
        String defaultText = getResources().getString(R.string.defaultText);
        int percent = (int) (process / (mWidth - padding - strokeWidth) * 100);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        int mTxtWidth = (int) mPaintText.measureText(finishedText, 0, defaultText.length());
        int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
        int x = getWidth() / 2 - mTxtWidth / 2; //文字在画布中的x坐标
        int y = getHeight() / 2 + mTxtHeight / 4; //文字在画布中的y坐标
        if (percent < 100) {
            canvas.drawText(percent + "%", x, y, mPaintText);
        } else {
            canvas.drawText(finishedText, x, y, mPaintText);
        }
    }

4.加入动画

最后就是加入动画效果了,让进度条动起来。我这里用到的是属性动画中的valueAnimator。这种动画不能直接修改view,它是类似于timer,需要我们传递一个数值范围和执行时间。比如说3秒内从1加到100。然后在接口回调时拿到当前的进度,执行view的invalidate()方法,刷新UI。

 //属性动画
    public void start() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mWidth - padding - strokeWidth);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            process = (float) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.start();
    }

完整代码

package com.example.floatingwindow.widget;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;

import com.example.floatingwindow.R;

public class HorizontalProgressView extends View {

    private Paint mPaint;
    private Paint mPaintRoundRect;
    private Paint mPaintText;
    private int mWidth;
    private int mHeight;
    private int padding = 5;
    private int strokeWidth = 8;
    private int textSize = 15;
    private long duration = 3500;
    private int round;
    private float process;

    public HorizontalProgressView(Context context) {
        super(context);
        init();
    }

    public HorizontalProgressView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public HorizontalProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    //初始化画笔
    private void init(){
        mPaintRoundRect = new Paint();//圆角矩形
        mPaintRoundRect.setColor(getResources().getColor(R.color.back));//圆角矩形颜色
        mPaintRoundRect.setAntiAlias(true);// 抗锯齿效果
        mPaintRoundRect.setStyle(Paint.Style.STROKE);//设置画笔样式
        mPaintRoundRect.setStrokeWidth(strokeWidth);//设置画笔宽度

        mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.inner));
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(strokeWidth);

        mPaintText = new Paint();
        mPaintText.setAntiAlias(true);
        mPaintText.setStyle(Paint.Style.FILL);
        mPaintText.setColor(getResources().getColor(R.color.back));
        mPaintText.setTextSize(sp2px(textSize));
    }

    public void setPadding(int padding) {
        this.padding = padding;
    }

    public void setStrokeWidth(int strokeWidth) {
        this.strokeWidth = strokeWidth;
    }

    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }

    public void setDuration(long duration) {
        this.duration = duration;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        //MeasureSpec.EXACTLY,精确尺寸
        if (widthSpecMode == MeasureSpec.EXACTLY || widthSpecMode == MeasureSpec.AT_MOST) {
            mWidth = widthSpecSize;
        } else {
            mWidth = 0;
        }
        //MeasureSpec.AT_MOST,最大尺寸,只要不超过父控件允许的最大尺寸即可,MeasureSpec.UNSPECIFIED未指定尺寸
        if (heightSpecMode == MeasureSpec.AT_MOST || heightSpecMode == MeasureSpec.UNSPECIFIED) {
            mHeight = defaultHeight();
        } else {
            mHeight = heightSpecSize;
        }
        //设置控件实际大小
        round = mHeight / 2;//圆角半径
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBackground(canvas);//绘制背景矩形
        drawProgress(canvas);//绘制进度
        updateText(canvas);//处理文字
    }

    private void drawBackground(Canvas canvas){
        RectF rectF = new RectF(padding, padding, mWidth - padding, mHeight - padding);//圆角矩形
        canvas.drawRoundRect(rectF, round, round, mPaintRoundRect);
    }

    private void drawProgress(Canvas canvas){
        if (process!=0){
            RectF rectProgress = new RectF(padding + strokeWidth, padding + strokeWidth, process, mHeight - padding - strokeWidth);//内部进度条
            canvas.drawRoundRect(rectProgress, round, round, mPaint);
        }
    }

    private void updateText(Canvas canvas) {
        String finishedText = getResources().getString(R.string.finished);
        String defaultText = getResources().getString(R.string.defaultText);
        int percent = (int) (process / (mWidth - padding - strokeWidth) * 100);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        int mTxtWidth = (int) mPaintText.measureText(finishedText, 0, defaultText.length());
        int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
        int x = getWidth() / 2 - mTxtWidth / 2; //文字在画布中的x坐标
        int y = getHeight() / 2 + mTxtHeight / 4; //文字在画布中的y坐标
        if (percent < 100) {
            canvas.drawText(percent + "%", x, y, mPaintText);
        } else {
            canvas.drawText(finishedText, x, y, mPaintText);
        }
    }

    //属性动画
    public void start() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mWidth - padding - strokeWidth);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(animation -> {
            process = (float) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.start();
    }

    private int sp2px(int sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                getResources().getDisplayMetrics());
    }

    //进度条默认高度,未设置高度时使用
    private int defaultHeight() {
        float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (20 * scale + 0.5f * (20 >= 0 ? 1 : -1));
    }

}

以上就是横向进度条的实现步骤,整体来说还是比较简单的,如果你对Android坐标系和canvas比较熟悉的话自定义view实现起来还是很容易的。

到此这篇关于Android实现绚丽的自定义进度条的文章就介绍到这了,更多相关Android自定义进度条内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android自定义View实现水平带数字百分比进度条

    这个进度条可以反映真实进度,并且完成百分比的文字时随着进度增加而移动的,所在位置也恰好是真实完成的百分比位置,效果如下: 思路如下:第一部分是左侧的蓝色直线,代表已经完成的进度:第二部分是右侧灰色的直线,代表未完成的进度:第三部分是红色的百分比的数字百分比文本,显示当前确切的完成进度. 最关键的部分就是要确定百分比文本的确切位置,这里用了paint的getTextBounds方法,得到文本的宽高,然后再精确确定它的位置. view代码如下: public class NumberProgress

  • Android自定义水平渐变进度条

    先看进度条的效果: 具体实现: 新建类,继承自View,在onDraw中进行绘制: import android.content.Context; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import and

  • Android自定义View实现渐变色进度条

    在网上看到一个进度条效果图,非常美观,如下: 进行效果分解: 1.渐变色,看起来颜色变化并不复杂,使用LinearGradient应该可以实现. 2.圆头,无非是画两个圆,外圆使用渐变色的颜色,内圆固定为白色. 3.灰底,还没有走到的进度部分为灰色. 4.进度值,使用文本来显示: 5.弧形的头部,考虑使用直线进行连接,或者使用曲线,例如贝塞尔曲线: 我首先初步实现了进度条的模样,发现样子有了,却不太美观. 反思了一下,我只是个写代码的,对于哪种比例比较美观,是没有清晰的认识的,所以,还是参考原图

  • Android自定义View实现圆形进度条

    本文实例为大家分享了Android自定义View实现圆形进度条的具体代码,供大家参考,具体内容如下 效果如下: 主要代码 CircularProgressView.java public class CircularProgressView extends View { private Paint mBackPaint, mProgPaint; // 绘制画笔 private RectF mRectF; // 绘制区域 private int[] mColorArray; // 圆环渐变色 pr

  • Android自定义View实现炫酷进度条

    本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyProgress"> <attr name="out_color" form

  • Android如何自定义View实现横向的双水波纹进度条

    目录 思路分析 功能实现 1.绘制圆角背景和圆角矩形边框 2.通过贝塞尔曲线实现双水波 3.设置动画使进度和水波纹变化 结语 网上垂直的水波纹进度条很多,但横向的很少,将垂直的水波纹改为水平的还遇到了些麻烦,现在完善后发布出来,希望遇到的人少躺点坑. 思路分析 整体效果可分为三个,绘制圆角背景和圆角矩形,绘制第一条和第二条水波浪,根据自定义进度变化效果. 功能实现 1.绘制圆角背景和圆角矩形边框 圆角矩形边框: private RectF rectBorder; if (rectBorder =

  • Android实现绚丽的自定义进度条

    目录 前言 效果图 实现步骤 1.绘制背景圆形矩形 2.绘制进度 3.绘制文字 4.加入动画 完整代码 前言 进度条是在Android项目中很常用的组件之一,如果想要理解它是怎么实现的,首先还需要了解自定义view和Android坐标系相关的知识,下面我来详细地介绍一下自定义进度条的实现过程. 本项目源码:https://gitee.com/tu_erhongjiang/android-progress-bar 效果图 实现步骤 1.绘制背景圆形矩形 首先要画出一个圆形矩形,RectF里面传递的

  • Android仿字节颜色自定义进度条

    本文实例为大家分享了Android仿字节颜色自定义进度条的具体代码,供大家参考,具体内容如下 效果展示 代码实现 第一步:编写自定义属性 res/values/attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyLoadingView"> <attr name="loadi

  • Android模拟实现华为系统升级进度条

    目录 前言 实现步骤 1.用DashPathEffect给paint加上虚线效果 2.画出进度条 3.绘制文字 4.加入动画效果 完整代码 前言 之前用华为Android系统的时候总是会想到这种虚线进度条是怎么实现的,因为直接用canvas的drawArc方法画出来的是实线,所以最近在网上搜了很多进度条相关的文章,也了解到了其中的原理,下面分享给大家.下面这两篇文章是我之前写的Android进度条相关的文章,有兴趣的朋友们可以看看: Android实现绚丽的自定义进度条 详解Android如何自

  • Android编程基于自定义View实现绚丽的圆形进度条功能示例

    本文实例讲述了Android编程基于自定义View实现绚丽的圆形进度条功能.分享给大家供大家参考,具体如下: 本文包含两个组件,首先上效果图: 1.ProgressBarView1(支持拖动): 2.ProgressBarView2(不同进度值显示不同颜色,不支持拖拽):   代码不多,注释也比较详细,全部贴上了: (一)ProgressBarView1: /** * 自定义绚丽的ProgressBar. */ public class ProgressBarView1 extends View

  • Android实现带数字的圆形进度条(自定义进度条)

    开发 设计搞了一个带圆形进度的进度条,在GitHub上逛了一圈,发现没有,自己撸吧. 先看界面效果: 主要思路是写一个继承ProgressBar的自定义View,不废话,直接上代码: package com.fun.progressbarwithnumber; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.g

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • android自定义进度条渐变圆形

    在安全卫生上,经常看到有圆形的进度条在转动,效果非常好看,于是就尝试去实现一下,具体实现过程不多说了,直接上效果图,先炫耀下. 效果图: 分析:比较常见于扫描结果.进度条等场景 利用canvas.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)绘制圆弧 Paint的一些属性定义粗细.颜色.样式等 LinearGradient实现颜色的线型渐变 同样的道理,可以画出长条进度

  • Android编程自定义进度条颜色的方法详解

    本文实例讲述了Android编程自定义进度条颜色的方法.分享给大家供大家参考,具体如下: 先看效果图: 老是提些各种需求问题,我觉得系统默认的颜色挺好的,但是Pk不过,谁叫我们不是需求人员呢,改吧! 这个没法了只能看源码了,还好下载了源码, sources\base\core\res\res\ 下应有尽有,修改进度条颜色只能找progress ,因为是改变样式,首先找styles.xml 找到xml后,进去找到: <style name="Widget.ProgressBar"&

  • Android编程实现自定义进度条颜色的方法

    本文实例讲述了Android编程实现自定义进度条颜色的方法.分享给大家供大家参考,具体如下: android 自定义进度条颜色 先看图 基于产品经理各种自定义需求,经过查阅了解,下面是自己对android自定义进度条的学习过程! 这个没法了只能看源码了,还好下载了源码, sources\base\core\res\res\  下应有尽有,修改进度条颜色只能找progress ,因为是改变样式,首先找styles.xml 找到xml后,进去找到 <style name="Widget.Pro

  • Android自定义进度条的圆角横向进度条实例详解

    1.本文将向你介绍自定义进度条的写法,比较简单,但还是有些知识点是需要注意的: invalidate()方法 RectF方法的应用 onMeasure方法的应用 2.原理 画3层圆角矩形,底层为黑色,第二层为灰色,最上一层为进度条颜色,示例图如下: 3.效果图   实现圆角进度条还有很多其他方法,比如在Progress控件里填充圆角图片,通过拉伸图片来达到预想的效果,虽然听起来很简单,但实现起来还是有些麻烦的. 4.解说方法 (1)invalidate()方法 invalidate()是用来刷新

随机推荐