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

转载请注明原博客地址: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




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gdutxiaoxu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值