效果展示
代码实现:
//自定义水平进度条
package com.lide.smartroomlide.customView; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.widget.ProgressBar; import com.lide.smartroomlide.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); } @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); 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 attributes final 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(); } @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(); } /** * 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()); } }
//水平带文字的对话框
package com.lide.smartroomlide.customView; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.widget.TextView; import com.lide.smartroomlide.R; /** * 可以设置文字并含有进度条的对话框 */ public class LoadingAlertDialog extends AlertDialog { public HorizontalProgressBarWithNumber progressImg; private TextView message; public LoadingAlertDialog(Context context) { super(context, R.style.LoadDialog); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_loading_rotate_layout); setCanceledOnTouchOutside(false); setCancelable(false); progressImg = (HorizontalProgressBarWithNumber) findViewById(R.id.bar_progress); message = (TextView) findViewById(R.id.tv_desc); } public void show(String msg) { super.show(); if (message != null) { message.setText(msg); } } /** * 在AlertDialog的 onStart() 生命周期里面执行开始动画 */ @Override protected void onStart() { super.onStart(); } @Override protected void onStop() { // progressImg.clearAnimation(); } }
//圆形带文字的进度条
package com.lide.smartroomlide.customView; 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.lide.smartroomlide.R; /** * 圆形进度条带有文字变化 */ public class RoundProgressBarWidthNumber extends HorizontalProgressBarWithNumber { /** * 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(); } }
attr_progress_bar 自定义进度条属性
<?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>
//对话框样式
<resources> <style name="LoadDialog" parent="android:style/Theme.Dialog"> <!--背景颜色及和透明程度--> <item name="android:windowBackground">@color/lx_black_transparent</item> <!--是否去除标题 --> <item name="android:windowNoTitle">true</item> <!--是否去除边框--> <item name="android:windowFrame">@null</item> <!--是否浮现在activity之上--> <item name="android:windowIsFloating">true</item> <!--是否模糊--> <item name="android:backgroundDimEnabled">false</item> </style> </resources>