Android自定义progressBar
通過繼承系統ProgressBar實現
效果圖
實現
HorizontalProgressBarWithNumber
自定義屬性
<?xml version="1.0" encoding="utf-8"?> <resources><declare-styleable name="HorizontalProgressBarWithNumber"><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>HorizontalProgressBarWithNumber
package com.zhy.view;import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.widget.ProgressBar;import com.zhy.library.view.R;public class HorizontalProgressBarWithNumber extends ProgressBar {private static final int DEFAULT_TEXT_SIZE = 10;private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;/*** painter of all drawing things*/protected Paint mPaint = new Paint();/*** color of progress number*/protected int mTextColor = DEFAULT_TEXT_COLOR;/*** size of text (sp)*/protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);/*** offset of draw progress*/protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);/*** height of reached progress bar*/protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);/*** color of reached bar*/protected int mReachedBarColor = DEFAULT_TEXT_COLOR;/*** color of unreached bar*/protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;/*** height of unreached progress bar*/protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);/*** view width except padding*/protected int mRealWidth;protected boolean mIfDrawText = true;protected static final int VISIBLE = 0;public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs){this(context, attrs, 0);}public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,int defStyle){super(context, attrs, defStyle);obtainStyledAttributes(attrs);mPaint.setTextSize(mTextSize);mPaint.setColor(mTextColor);}@Overrideprotected 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);if (specMode == MeasureSpec.EXACTLY){result = specSize;} else{float textHeight = (mPaint.descent() - mPaint.ascent());result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachedProgressBarHeight,mUnReachedProgressBarHeight), Math.abs(textHeight)));if (specMode == MeasureSpec.AT_MOST){result = Math.min(result, specSize);}}return result;}/*** get the styled attributes* * @param attrs*/private void obtainStyledAttributes(AttributeSet attrs){// init values from custom attributesfinal TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);mTextColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,DEFAULT_TEXT_COLOR);mTextSize = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_size,mTextSize);mReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,mTextColor);mUnReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,DEFAULT_COLOR_UNREACHED_COLOR);mReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,mReachedProgressBarHeight);mUnReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,mUnReachedProgressBarHeight);mTextOffset = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,mTextOffset);int textVisible = attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,VISIBLE);if (textVisible != VISIBLE){mIfDrawText = false;}attributes.recycle();}@Overrideprotected 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 barfloat 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 boundif (mIfDrawText){mPaint.setColor(mTextColor);canvas.drawText(text, progressPosX, -textHeight, mPaint);}// draw unreached barif (!noNeedBg){float start = progressPosX + mTextOffset / 2 + textWidth;mPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawLine(start, 0, mRealWidth, 0, mPaint);}canvas.restore();}/*** dp 2 px* * @param dpVal*/protected int dp2px(int dpVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}/*** sp 2 px* * @param spVal* @return*/protected int sp2px(int spVal){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal, getResources().getDisplayMetrics());}}主要重寫了onMeasure與onDraw方法
RoundProgressBarWidthNumber
圓形的進度條和橫向的進度條基本變量都是一致的,于是我就讓RoundProgressBarWidthNumber extends HorizontalProgressBarWithNumber 了。
然后需要改變的就是測量和onDraw了:
完整代碼
package com.zhy.view;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;import com.zhy.library.view.R;public class RoundProgressBarWidthNumber extendsHorizontalProgressBarWithNumber {/*** 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值要么不設置,要么全部設置*/@Overrideprotected 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);}@Overrideprotected 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 barmPaint.setColor(mUnReachedBarColor);mPaint.setStrokeWidth(mUnReachedProgressBarHeight);canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);// draw reached barmPaint.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 textmPaint.setStyle(Style.FILL);canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight,mPaint);canvas.restore();}}首先獲取它的專有屬性mRadius,然后根據此屬性去測量,測量完成繪制;
繪制的過程呢?
先繪制一個細一點的圓,然后繪制一個粗一點的弧度,二者疊在一起就行。文本呢,繪制在中間~~~總體,沒什么代碼量。
好了,兩個進度條就到這了,是不是發現簡單很多。總體設計上,存在些問題,如果抽取一個BaseProgressBar用于獲取公共的屬性;然后不同樣子的進度條繼承分別實現自己的測量和樣子,這樣結構可能會清晰些~
使用
布局文件
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:zhy="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="25dp" ><com.zhy.view.HorizontalProgressBarWithNumberandroid:id="@+id/id_progressbar01"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp" /><com.zhy.view.HorizontalProgressBarWithNumberandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="50"zhy:progress_text_color="#ffF53B03"zhy:progress_unreached_color="#ffF7C6B7" /><com.zhy.view.RoundProgressBarWidthNumberandroid:id="@+id/id_progress02"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="30" /><com.zhy.view.RoundProgressBarWidthNumberandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="50dip"android:padding="5dp"android:progress="50"zhy:progress_reached_bar_height="20dp"zhy:progress_text_color="#ffF53B03"zhy:radius="60dp" /></LinearLayout></ScrollView>MainActivity
package com.zhy.sample.progressbar;import android.app.Activity; import android.os.Bundle; import android.os.Handler;import com.zhy.annotation.Log; import com.zhy.view.HorizontalProgressBarWithNumber;public class MainActivity extends Activity {private HorizontalProgressBarWithNumber mProgressBar;private static final int MSG_PROGRESS_UPDATE = 0x110;private Handler mHandler = new Handler() {@Logpublic void handleMessage(android.os.Message msg) {int progress = mProgressBar.getProgress();mProgressBar.setProgress(++progress);if (progress >= 100) {mHandler.removeMessages(MSG_PROGRESS_UPDATE);}mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);};};@Log@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);}}知識點
- paint.ascent()和paint.descent()
1.基準點是baseline
2.ascent:是baseline之上至字符最高處的距離
3.descent:是baseline之下至字符最低處的距離
4.leading:是上一行字符的descent到下一行的ascent之間的距離,也就是相鄰行間的空白距離
5.top:是指的是最高字符到baseline的值,即ascent的最大值
6.bottom:是指最低字符到baseline的值,即descent的最大值
- View.resolveSize(int size,int measureSpec)
代碼如下
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:if (specSize < size) {result = specSize | MEASURED_STATE_TOO_SMALL;} else {result = size;}break;case MeasureSpec.EXACTLY:result = specSize;break;}return result | (childMeasuredState&MEASURED_STATE_MASK);}源代碼下載
源代碼
參考鏈接
Android 打造形形色色的進度條 實現可以如此簡單 - Hongyang - 博客頻道 - CSDN.NET
轉載于:https://www.cnblogs.com/jjx2013/p/6223638.html
總結
以上是生活随笔為你收集整理的Android自定义progressBar的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MYSQL----myownstars(
- 下一篇: Java四种线程池