Android自定义控件实现一个带文本与数字的圆形进度条

实现的效果图如下所示:

第一步:绘制下方有缺口的空心圆,称为外围大弧吧

anvas.clipRect(0, 0, mWidth, mHeight / 2 + radius - textHeight * 3 / 4);

第二步:计算绘制圆弧进度条时的起始角度,设置为外围大弧的左端点为进度值得起点,扫过的角度所占外围大弧的百分比就是进度值

第三步:绘制数字、文字、百分号

第四步:使用Handler Runnable 和DecelerateInterpolator是进度条和数字动起来

测试代码:

final CustomCircleBar circle=(CustomCircleBar)findViewById(R.id.win_home);
circle.setPercent(10);
circle.setCustomText("呵呵");
circle.setProgessColor(getResources().getColor(R.color.blue));
final Random random=new Random();
circle.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v){
        circle.setPercent(random.nextInt(100));
    }
});

完成代码如下:

public class CustomCircleBar extends View {
    private Context context;
    /*进度值*/
    private int percent;
    /*颜色值*/
    private int mProgessColor;
    /*下边的文字名称*/
    private String mCustomText;
    /*外圈圆环的画笔*/
    private Paint paintBar = new Paint();
    /*下边文字的画笔*/
    private Paint paintText = new Paint();
    /*动态获取属性值*/
    private TypedValue typedValue;
    /*先加速后减速*/
    DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
    /*动画持续时间*/
    private int duration = 10;
    private int curTime = 0;
    public CustomCircleBar(Context context) {
        super(context);
        this.context=context;
        init();
    }

    public CustomCircleBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        init();
    }

    public CustomCircleBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context=context;
        init();
    }

    public void setPercent(int percent) {
        this.percent = percent;
        /*isShown():Returns the visibility of this view and all of its ancestors*/
        if (isShown()) {
            /*设置进度后重新开始一次动画*/
            curTime=0;
            this.invalidate();
        }
    }

    public void setProgessColor(int mProgessColor) {
        this.mProgessColor = mProgessColor;
        if (isShown()) {
            this.invalidate();
        }
    }

    public void setCustomText(String mCustomText) {
        this.mCustomText = mCustomText;
    }

    private Handler mHandler = new Handler();
    private Runnable mAnimation = new Runnable() {
        @Override
        public void run() {
            if (curTime < duration) {
                curTime++;
                /*导致重绘,调用onDraw,onDraw最后调用
                *  mHandler.postDelayed(mAnimation, 20);更新进度条,界面重绘
                *  每次20毫秒,绘制10次,因此动画时间200毫秒*/
                CustomCircleBar.this.invalidate();
            }
        }
    };

    private void init() {
        /*数据初始化,没有设置属性时候的默认值*/
        percent = 0;
        mProgessColor=Color.rgb(95,112,72);
        mCustomText="Home";
        typedValue=new TypedValue();
        context.getTheme().resolveAttribute(R.attr.maintextclor,typedValue,true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float mWidth = getWidth();
        float mHeight = getHeight();
        /*下边是进度条画笔的设置*/
        /** Restores the paint to its default settings. */
        paintBar.reset();
        /*圆环宽度4个像素*/
        paintBar.setStrokeWidth(4);
        /*空心圆环而非填充的额扇形*/
        paintBar.setStyle(Paint.Style.STROKE);
        paintBar.setAntiAlias(true);
        paintBar.setColor(mProgessColor);
        /*调整下不透明度,使边框弧和进度条区分开*/
        paintBar.setAlpha(80);
        /*接下来是文字画笔的设置*/
        paintText.setTextSize(20);
        paintText.setColor(getResources().getColor(typedValue.resourceId));
        paintText.setStyle(Paint.Style.STROKE);
        paintText.setAntiAlias(true);
        /*从中间开始绘制文本*/
        paintText.setTextAlign(Paint.Align.CENTER);
        /*测量文字大小*/
        Paint.FontMetrics fontMetrics = paintText.getFontMetrics();
        /*计算文字高度*/
        float textHeight = fontMetrics.bottom - fontMetrics.top;
        /*计算圆的半径*/
        float radius = Math.min(mWidth, mHeight) / 2 - 10;
        /*  ? save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
            ? restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。*/
        /*保存画布,绘制进度条*/
        canvas.save();
        /*clipRect:该方法用于裁剪画布,也就是设置画布的显示区域
        调用clipRect()方法后,只会显示被裁剪的区域,之外的区域将不会显示 */
        canvas.clipRect(0, 0, mWidth, mHeight / 2 + radius - textHeight * 3 / 4);
        /*因为clipRect的原因,外边的圆环下边留个缺口绘制文字*/
        canvas.drawCircle(mWidth / 2, mHeight / 2, radius, paintBar);

        /*三角函数计算,下方缺口扇形的角度的一半*/
        float theta_offset = (float) Math.acos((radius - textHeight / 2) / radius);
        /*大弧围成的扇形的角度*/
        float theta_full = 360 - 2 * theta_offset;
        /*进度值围成的弧对应的角度*/
        float thetaProcess = mDecelerateInterpolator.getInterpolation(1.0f * curTime / duration) * percent * theta_full / 100;
        /*设置进度值颜色完全不透明*/
        paintBar.setAlpha(255);
        paintBar.setColor(mProgessColor);
        /*注意弧形的起始角度,下边因显示文字导致圆环断开成一条弧,弧有左右两个端点,从左端点开始画弧*/
        canvas.drawArc(new RectF(mWidth / 2 - radius, mHeight / 2 - radius, mWidth / 2 + radius, mHeight / 2 + radius), theta_offset+90, thetaProcess, false, paintBar);
        /*恢复画布*/
        canvas.restore();
        /*开始绘制文字*/
        paintText.setTextSize(20);
        fontMetrics = paintText.getFontMetrics();
        float textBaseLineOffset = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        canvas.drawText(mCustomText, mWidth / 2, mHeight / 2 + radius - textHeight / 2 + textBaseLineOffset, paintText);

        /*绘制百分号*/
        paintText.setTextSize(mHeight * 1 / 8);
        fontMetrics = paintText.getFontMetrics();
        textBaseLineOffset = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        canvas.drawText("%", mWidth / 2, mHeight / 2 + radius / 3 + textBaseLineOffset, paintText);

        /*绘制百分比*/
        paintText.setTextSize(mHeight * 3 / 8);
        canvas.drawText("" + (int)(percent*mDecelerateInterpolator.getInterpolation(1.0f * curTime / duration)), mWidth / 2, mHeight / 2, paintText);
        /*20毫秒后执行动画*/
        mHandler.postDelayed(mAnimation, 20);
    }
}
时间: 2024-09-27 04:30:05

Android自定义控件实现一个带文本与数字的圆形进度条的相关文章

一个不是那么优美的圆形进度条续(基本还原原应用里面的效果)

之前帮别人写了一个不是那么优美的圆形进度条,效果图大家也看过了.但是后某人不满意,说原应用是倒计时时间最后5s,才开始显示数字的,同时转完一圈需要的时间只能是30s左右.然后我掐时间看了一下虽然总时间设置的是30s,但是总共转完一圈却耗费了50多秒的样子. 问题出来了: 1. 转圈总时间30s不正确 2. 数字显示时间不正确 3. 数字1的动画没原应用的好(2144手机令牌) 花了一个小时搞了一下,忍不住终于射出来了什么东西,解决了上面的3个问题(请看1从有到无):国际惯例效果图先行,先看下改善

iOS开发笔记-根据frame大小动态调整fontSize的自适应文本及圆形进度条控件的实现

最近同样是新App,设计稿里出现一种圆形进度条的设计,如下: 想了想,圆形进度条实现起来不难,但是其中显示百分比的文本确需要自适应,虽然可以使用时自己设定文本字体的大小,但是这样显得很麻烦,也很low. 查了一圈,目前实现的自适应UILabel,都是根据font大小动态调整frame的size,并不能满足我们的需求.  那么问题来了 如何实现一种能够根据frame大小自适应调整文本font size的圆形进度条呢? 我的实现思路很简单,首先计算出能够给予UILabel的frame最大尺寸,然后根

android控件---自定义带文本的ImageButton

由于SDK提供的ImageButton只能添加图片,不能添加文字:而Button控件添加的文字只能显示在图片内部:当我们需要添加文字在图片外部时就不能满足我们的需求了,顾只能自己写个自定义ImageButton.说是ImageButton,其实并不是继承于ImageButton,而是从LinearLayout继承,由于LinearLayout是线性排列,通过setOrientation(LinearLayout.VERTICAL)的方式达到View垂直排列的目的,所以很简单,只需要添加两个Vie

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

Android 带进度的圆形进度条

extends:http://blog.csdn.net/xiaanming/article/details/10298163 转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项

Android自定义控件系列之应用篇——圆形进度条

一.概述 在上一篇博文中,我们给大家介绍了Android自定义控件系列的基础篇.链接:http://www.cnblogs.com/jerehedu/p/4360066.html 这一篇博文中,我们将在基础篇的基础上,再通过重写ondraw()方法和自定义属性实现圆形进度条,效果如图所示: 二.实现步骤   1.  编写自定义组件MyCircleProgress扩展View public class MyCircleProgress extends View { - } 2.  在MyCircl

Android绘制圆形进度条

一.背景介绍 我们在项目中,经常会见到圆形进度条,看起来很美观.直观.刚好最近项目中有这样的需求,记录一下,顺便回顾下自定义View的知识. 二.实现思路 自定义View,就是在画布中绘制View,需要重写onDraw方法.该View可以拆分成以下几部分: 1)需要画一个浅绿色的圆 2)需要画一个白色的圆 3)圆圈中有进度数字的显示 4)圆圈中可以自定义顶部和底部不同文案的提示 三.主要方法介绍 1.drawArc:由上图可以看出,该圆需要画出圆弧表示进度,所以选择drawArc(RectF o

Android 高手进阶,自己定义圆形进度条

背景介绍 在Android 开发中,我们常常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,许多时候须要我们自定义控件,在开发的过程中.我们公司遇到了一种须要自己写的一个自定义带进度的圆形进度条,看起来很的绚丽,当然另一些其它的.比方:水纹形的圆形进度条等效果都是很nice的.假设哪位朋友有实现,希望分享出来,我也好学习学习. 好了多的不说.接下来,我们就来看看来怎样实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/arti

Android 高手进阶,自定义圆形进度条

背景介绍 在Android 开发中,我们经常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,很多时候需要我们自己定义控件,在开发的过程中,我们公司遇到了一种需要自己写的一个自定义带进度的圆形进度条,看起来非常的绚丽,当然还有一些其他的,比如:水纹形的圆形进度条等效果都是非常nice的.如果哪位朋友有实现,希望分享出来,我也好学习学习.好了多的不说,接下来,我们就来看看来如何实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/a