自定义ProgressBar(包括自定义图片,带进度的圆形进度条、长方形进度条)

原创 2016年05月31日 15:20:01

转载请注明原博客地址:http://blog.csdn.net/gdutxiaoxu/article/details/51545889

参考博客:http://blog.csdn.net/lmj623565791?viewmode=contents



ProgressBar简介


继承于View类,直接子类有AbsSeekBar和ContentLoadingProgressBar,其中AbsSeekBar的子类有SeekBar和RatingBar,可见这二者也是基于ProgressBar实现的。


1、ProgressBar有两个进度,一个是Android:progress,另一个是android:secondaryProgress。后者主要是为缓存需要所涉及的,比如在看网络视频时候都会有一个缓存的进度条以及还要一个播放的进度,在这里缓存的进度就可以是android:secondaryProgress,而播放进度就是android:progress,有了secondProgress,可以很方便定制ProgressBar。

 2、ProgressBar分为确定的和不确定的,确定的是我们能明确看到进度,相反不确定的就是不清楚、不确定一个操作需要多长时间来完成,这个时候就需要用的不确定的ProgressBar了。属性android:indeterminate如果设置为true的话,那么ProgressBar就可能是圆形的滚动条或者水平的滚动条(由样式决定),但是我们一般时候,是直接使用Style类型来区分圆形还是水平ProgressBar的。

3、ProgressBar的样式设定其实有两种方式,在API文档中说明的方式如下:

  • Widget.ProgressBar.Horizontal
  • Widget.ProgressBar.Small
  • Widget.ProgressBar.Large
  • Widget.ProgressBar.Inverse
  • Widget.ProgressBar.Small.Inverse
  • Widget.ProgressBar.Large.Inverse
  使用的时候可以这样:style="@android:style/Widget.ProgressBar.Small",另外还有一种方式就是使用系统的attr,下面的方式是系统的style:

  • style="?android:attr/progressBarStyle" 
  • style="?android:attr/progressBarStyleHorizontal" 
  • style="?android:attr/progressBarStyleInverse" 
  • style="?android:attr/progressBarStyleLarge" 
  • style="?android:attr/progressBarStyleLargeInverse" 
  • style="?android:attr/progressBarStyleSmall" 
  • style="?android:attr/progressBarStyleSmallInverse" 
  • style="?android:attr/progressBarStyleSmallTitle"                         
  •                
先看一下效果图


源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git
1 修改ProgressBar的图片

1)第一个效果的实现非常简单


只需要修改ProgressBar的style即可
   
  <style name="progressBar_custom_drawable" parent="@android:style/Widget.ProgressBar.Small">
        <item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item>
        <item name="android:minWidth">25dp</item>
        <item name="android:minHeight">25dp</item>
        <item name="android:maxWidth">60dp</item>
        <item name="android:maxHeight">60dp</item>
    </style>

其中修改属性即可更改为我们想要的效果
 <item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item>
2)这个形状我们可以借助代码实现


在Drawable目录下新建一个XML文件



<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0"
        android:pivotX="50%" android:pivotY="50%" android:toDegrees="360">
      
    <shape android:innerRadiusRatio="3" android:shape="ring" android:thicknessRatio="8"
           android:useLevel="false">
            
        <gradient android:centerColor="#FFFFFF" android:centerY="0.50"
                  android:endColor="#1E90FF"
                  android:startColor="#000000" android:type="sweep"
        android:useLevel="false" />
    </shape>
</rotate>

2 自定义长方形进度条




这种效果我们是通过继承ProgressBar实现的
a 先讲一下实现思路
横向那个进度条,主要是通过是通过Canvas类的drawLine()和drawText()方法实现的,
1)要解决的问题,怎样拿到拿到控件的宽度,(不了解的请先自行了解View的绘制原理,本篇博客的重点不在这里,就不详细说了,下面会给出测量的代码
2)拿到宽度以后,我们再通过getProgress()拿到进度,按比例控制绘制线的长短,这样就实现了。
为了控件使用起来方便,我们使用到了自定义属性,如果多自定义属性不熟悉的,建议参考鸿洋的这篇博客:http://blog.csdn.net/lmj623565791/article/details/45022631
下面给出源代码

1)在value目录下新建attr_progress_bar xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="BaseProgressBar">
        <attr name="progress_unreached_color" format="color" />
        <attr name="progress_reached_color" format="color" />
        <attr name="progress_reached_bar_height" format="dimension" />
        <attr name="progress_unreached_bar_height" format="dimension" />
        <attr name="progress_text_size" format="dimension" />
        <attr name="progress_text_color" format="color" />
        <attr name="progress_text_offset" format="dimension" />
        <attr name="progress_text_visibility" format="enum">
            <enum name="visible" value="0" />
            <enum name="invisible" value="1" />
        </attr>
    </declare-styleable>

    <declare-styleable name="RoundProgressBarWidthNumber">
        <attr name="radius" format="dimension" />
    </declare-styleable>
</resources>
2)在构造器里面获取我们的自定义属性,为了代码的复用,我们把它放到基类BaseProgressBar

/**
 * get the styled attributes
 *
 * @param attrs
 */
private void obtainStyledAttributes(AttributeSet attrs) {
    // init values from custom attributes
    final TypedArray attributes = getContext().obtainStyledAttributes(
            attrs, R.styleable.BaseProgressBar);

    mTextColor = attributes
            .getColor(
                    R.styleable.BaseProgressBar_progress_text_color,
                    DEFAULT_TEXT_COLOR);
    mTextSize = (int) attributes.getDimension(
            R.styleable.BaseProgressBar_progress_text_size,
            mTextSize);

    mReachedBarColor = attributes
            .getColor(
                    R.styleable.BaseProgressBar_progress_reached_color,
                    mTextColor);
    mUnReachedBarColor = attributes
            .getColor(
                    R.styleable.BaseProgressBar_progress_unreached_color,
                    DEFAULT_COLOR_UNREACHED_COLOR);
    mReachedProgressBarHeight = (int) attributes
            .getDimension(
                    R.styleable.BaseProgressBar_progress_reached_bar_height,
                    mReachedProgressBarHeight);
    mUnReachedProgressBarHeight = (int) attributes
            .getDimension(
                    R.styleable.BaseProgressBar_progress_unreached_bar_height,
                    mUnReachedProgressBarHeight);
    mTextOffset = (int) attributes
            .getDimension(
                    R.styleable.BaseProgressBar_progress_text_offset,
                    mTextOffset);

    int textVisible = attributes
            .getInt(R.styleable.BaseProgressBar_progress_text_visibility,
                    VISIBLE);
    if (textVisible != VISIBLE) {
        mIfDrawText = false;
    }
    attributes.recycle();
}

public BaseProgressBar(Context context, AttributeSet attrs,
                       int defStyle) {
    super(context, attrs, defStyle);
    obtainStyledAttributes(attrs);
    mPaint.setTextSize(mTextSize);
    mPaint.setColor(mTextColor);
}
3)在onMeasure里面拿到我们空间的高度

<pre name="code" class="java">@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = measureHeight(heightMeasureSpec);
    setMeasuredDimension(width, height);

    mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
}

   
   private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
//        测量模式等于 MeasureSpec.EXACTLY,交给系统自己处理
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
//             测量模式不等于 MeasureSpec.EXACTLY
        } else {
           
//            测量模式等于MeasureSpec.UNSPECIFIE的时候自己处理
            float textHeight = (mPaint.descent() - mPaint.ascent());
            result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
                    Math.max(mReachedProgressBarHeight,
                            mUnReachedProgressBarHeight), Math.abs(textHeight)));
//            测量模式等于MeasureSpec.AT_MOST的时候,取较小的一个
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }



4)在onDraw里面绘制

 @Override
    protected synchronized void onDraw(Canvas canvas) {

        canvas.save();
        canvas.translate(getPaddingLeft(), getHeight() / 2);

        boolean noNeedBg = false;
        float radio = getProgress() * 1.0f / getMax();
        float progressPosX = (int) (mRealWidth * radio);
        String text = getProgress() + "%";
        // mPaint.getTextBounds(text, 0, text.length(), mTextBound);

        float textWidth = mPaint.measureText(text);
        float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

        if (progressPosX + textWidth > mRealWidth) {
            progressPosX = mRealWidth - textWidth;
            noNeedBg = true;
        }

        // draw reached bar
        float endX = progressPosX - mTextOffset / 2;
        if (endX > 0) {
            mPaint.setColor(mReachedBarColor);
            mPaint.setStrokeWidth(mReachedProgressBarHeight);
            canvas.drawLine(0, 0, endX, 0, mPaint);
        }
        // draw progress bar
        // measure text bound
        if (mIfDrawText) {
            mPaint.setColor(mTextColor);
            canvas.drawText(text, progressPosX, -textHeight, mPaint);
        }

        // draw unreached bar
        if (!noNeedBg) {
            float start = progressPosX + mTextOffset / 2 + textWidth;
            mPaint.setColor(mUnReachedBarColor);
            mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
            canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
        }

        canvas.restore();

    }

到这里,实现思已经完毕
源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git

3 自定义圆形进度条


实现思路
1)继承BaseProgressBar,在构造器里面获取我们需要的自定义属性
2)在onMeasure里面拿到我们空间的高度
3)在onDraw里面绘制圆和文本(先绘制一个细一点的圆,然后绘制一个粗一点的弧度,二者叠在一起就行。文本呢,绘制在中间)
代码如下
package com.xujun.administrator.customprogressbar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;

public class RoundProgressBarWidthNumber extends
        BaseProgressBar {
    /**
     * mRadius of view
     */
    private int mRadius = dp2px(30);
    private int mMaxPaintWidth;

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

    public RoundProgressBarWidthNumber(Context context, AttributeSet attrs) {
        super(context, attrs);

        mReachedProgressBarHeight = (int) (mUnReachedProgressBarHeight * 2.5f);
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.RoundProgressBarWidthNumber);
        mRadius = (int) ta.getDimension(
                R.styleable.RoundProgressBarWidthNumber_radius, mRadius);
        ta.recycle();

        mPaint.setStyle(Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStrokeCap(Cap.ROUND);

    }

    /**
     * 这里默认在布局中padding值要么不设置,要么全部设置
     */
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec,
                                          int heightMeasureSpec) {

        mMaxPaintWidth = Math.max(mReachedProgressBarHeight,
                mUnReachedProgressBarHeight);
        int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft()
                + getPaddingRight();
        int width = resolveSize(expect, widthMeasureSpec);
        int height = resolveSize(expect, heightMeasureSpec);
        int realWidth = Math.min(width, height);

        mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;

        setMeasuredDimension(realWidth, realWidth);

    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {

        String text = getProgress() + "%";
        float textWidth = mPaint.measureText(text);
        float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

        canvas.save();
        canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop()
                + mMaxPaintWidth / 2);
        mPaint.setStyle(Style.STROKE);
        // draw unreaded bar
        mPaint.setColor(mUnReachedBarColor);
        mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
        // draw reached bar
        mPaint.setColor(mReachedBarColor);
        mPaint.setStrokeWidth(mReachedProgressBarHeight);
        float sweepAngle = getProgress() * 1.0f / getMax() * 360;
        canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0,
                sweepAngle, false, mPaint);
        // draw text
        mPaint.setStyle(Style.FILL);
        canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight,
                mPaint);

        canvas.restore();

    }

}
源代码下载地址:https://github.com/gdutxiaoxu/CustomProgressBar.git

转载请注明原博客地址:http://blog.csdn.net/gdutxiaoxu/article/details/51545889

参考博客:http://blog.csdn.net/lmj623565791?viewmode=contents




版权声明:本文为博主原创文章,未经博主允许不得转载。

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

很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如o...

android 圆形渐变进度条CircleProgressBar的开源框架

1.类似QQ健康中当日步数圆弧显示ColorArcProgressBar https://github.com/Shinelw/ColorArcProgressBar 2 支持进度条渐变的 ...

自定义圆形进度条 自定义倒计时进度条

Android自定义View:自定义圆形进度条 自定义倒计时进度条。继承自Textview,可以顺序旋转,可以倒叙旋转,可以设置进度条颜色,填充颜色,可以设置进度条宽度,可以设置填充颜色点击效果,文字...

自定义View之简单自定义圆形进度条

达到的效果如下: 从上面的效果可以看出,主要有以下几个自定义属性: 1、背景颜色 2、进度扇形颜色 3、半径 4、起始角度 因此,在attrs.xml中定义如下属性: ...

自定义的圆形进度条,还可以自己扩展

由于项目需求,于是就自己研究了下,写了这个自定义View,可以根据自己的需求进行更改,已经对外提供了获取当前值和更改颜色的方法,还可以调整进度的速度,完全根据自己的需求进行扩展,第一次写博客,草草了事...
  • zdc9023
  • zdc9023
  • 2015年12月10日 17:53
  • 482

【Android进度条】三种方式实现自定义圆形进度条ProgressBar

一、通过动画实现定义res/anim/loading.xml如下: 二、通过自定义颜色实现定义res/drawable/progress_small.xm...

ProgressBar长方形进度条,item背景当进度条

效果图如下: 首先要确定进度条的样式:  style.xml                 false         @android:drawable/progress_horiz...

Android绘图:自定义View之——矩形进度条、圆环进度条、填充型进度条、时钟

主函数 矩形进度条自定义View 矩形进度条的布局 成像图 圆环形进度条自定义View 圆环形进度条的布局 成像图 填充型进度条自定义View 填充型进度条布局 成像图 时钟自定义View 时钟自定义...

圆形进度条,可设置内外环,多彩

今天做一个健身的项目,客户需要一个圆形的进度条来查看个人的运动记录等,做了一些功课之后贴出代码大家一起分享下 新建一个继承UIView类 .h文件 @interface MyProgressVie...

自定义横向带刻度progressbar

自定义横向的带渐变色的progressbar进度条TickProgressBar。用到的主要知识点 1,LinearGradient 渐变。2,通过PorterDuffXfermode的PorterD...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自定义ProgressBar(包括自定义图片,带进度的圆形进度条、长方形进度条)
举报原因:
原因补充:

(最多只允许输入30个字)