前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义ProgressBar(包括自定义图片,带进度的圆形进度条、长方形进度条)

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

作者头像
程序员徐公
发布2018-09-18 17:02:49
8.5K0
发布2018-09-18 17:02:49
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1341920

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

代码语言:javascript
复制
  <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>

其中修改属性即可更改为我们想要的效果

代码语言:javascript
复制
 <item name="android:indeterminateDrawable">@drawable/progressbar_circle_1</item>

2)这个形状我们可以借助代码实现

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

代码语言:javascript
复制
<?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文件

代码语言:javascript
复制
<?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

代码语言:javascript
复制
代码语言:javascript
复制
/**
 * 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里面拿到我们空间的高度

代码语言:javascript
复制
<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;
    }
代码语言:javascript
复制

4)在onDraw里面绘制

代码语言:javascript
复制
 @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里面绘制圆和文本(先绘制一个细一点的圆,然后绘制一个粗一点的弧度,二者叠在一起就行。文本呢,绘制在中间)

代码如下

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年05月31日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ProgressBar简介
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档