————自定義PercentProgressBar繼承自View套硼,五個自定義屬性progressWidth(進度條寬度)垫毙,progressBackColor(進度條背景色)霹疫,progressFrontColor(進度條前景色),percentTextSize(百分比文字大凶劢妗)丽蝎,percentTextColor(百分比文字顏色),可在布局文件中直接使用毫痕。
如需下載源碼征峦,請訪問
https://github.com/fengchuanfang/PercentProgressBarDemo1
文章原創(chuàng),轉(zhuǎn)載請注明出處:
自定義Material Design風格帶滾動百分比的圓形進度條
運行效果如下:
引入步驟
訪問git地址下載源碼,拷貝com.feng.edward.percentprogressbardemo1.view包下的PercentProgressBar類和attrs.xml中的PercentProgressBar的五項屬性
或者新建java類PercentProgressBar消请,直接復制以下代碼栏笆,再將attrs.xml中的代碼放入項目對應attrs文件中。便可以在布局文件中直接使用臊泰。
package com.feng.edward.percentprogressbardemo1.view;
import com.feng.edward.percentprogressbardemo1.R;
import com.feng.edward.percentprogressbardemo1.util.DimensionUtils;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* 功能描述:帶滾動百分比的圓形進度條
*
* @author (作者) edward(馮豐楓)
* @link http://www.reibang.com/u/f7176d6d53d2
* 創(chuàng)建時間: 2018/4/16 0016
*/
public class PercentProgressBar extends View {
private Paint
progressBackPaint, //進度條背景畫筆
progressFrontPaint,//進度條前景畫筆
percentTextPaint; //百分比文字畫筆
private RectF
progressRectF,//進度條圓弧所在的矩形
percentTextRectF;//百分比文字所在的矩形
private Path percentTextPath; //百分比文字所在的路徑
private float percentTextRadius; //百分比文字圓弧的半徑
private float progressPaintWidth; //進度條畫筆的寬度
private int percentProgress;//百分比進度(0 ~ 100)
public PercentProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PercentProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.PercentProgressBar, defStyleAttr, 0);
//初始化進度條畫筆的寬度
progressPaintWidth = attributes.getDimension(R.styleable.PercentProgressBar_progressWidth, DimensionUtils.dip2px(context, 10));
//初始化百分比文字的大小
float percentTextPaintSize = attributes.getDimensionPixelSize(R.styleable.PercentProgressBar_percentTextSize, DimensionUtils.sp2px(context, 10));
int progressBackColor = attributes.getColor(R.styleable.PercentProgressBar_progressBackColor, 0xffaaaaaa);
int progressFrontColor = attributes.getColor(R.styleable.PercentProgressBar_progressFrontColor, 0xffFF4081);
int percentTextColor = attributes.getColor(R.styleable.PercentProgressBar_percentTextColor, 0xffff0077);
attributes.recycle();
//初始化進度條背景畫筆
progressBackPaint = new Paint();
progressBackPaint.setColor(progressBackColor);
progressBackPaint.setStrokeWidth(progressPaintWidth);
progressBackPaint.setAntiAlias(true);
progressBackPaint.setStyle(Paint.Style.STROKE);
//初始化進度條前景畫筆
progressFrontPaint = new Paint();
progressFrontPaint.setColor(progressFrontColor);
progressFrontPaint.setStrokeWidth(progressPaintWidth);
progressFrontPaint.setAntiAlias(true);
progressFrontPaint.setStyle(Paint.Style.STROKE);
//初始化百分比文字畫筆
percentTextPaint = new Paint();
percentTextPaint.setColor(percentTextColor);
percentTextPaint.setTextSize(percentTextPaintSize);// 設置文字畫筆的尺寸(px)
percentTextPaint.setAntiAlias(true);
percentTextPaint.setStyle(Paint.Style.STROKE);
percentTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
//初始化百分比文字路徑
percentTextPath = new Path();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();// 獲取控件的layout_width
int height = getMeasuredHeight(); // 獲取控件的layout_height
//獲取內(nèi)切圓圓心坐標
int centerX = width / 2;
int centerY = height / 2;
int radius = Math.min(width, height) / 2;//獲取控件內(nèi)切圓的半徑
Rect rect = new Rect();
percentTextPaint.getTextBounds("100%", 0, "100%".length(), rect);//獲取最大百分比文字的高度
int textHeight = rect.height();
//比較進度條的寬度和百分比文字的高度蛉加,去兩者中較大者,用以計算進度條的半徑缸逃,保證精度條和百分比文字互為中心
float radiusArc = radius - (progressPaintWidth > textHeight ? progressPaintWidth / 2 : textHeight / 2);
//初始化進度條圓弧所在的矩形
progressRectF = new RectF();
progressRectF.left = centerX - radiusArc;
progressRectF.top = centerY - radiusArc;
progressRectF.right = centerX + radiusArc;
progressRectF.bottom = centerY + radiusArc;
percentTextRadius = radiusArc - textHeight / 2;//計算百分比文字圓弧的半徑
//初始化百分比文字路徑所在的矩形
percentTextRectF = new RectF();
percentTextRectF.left = centerX - percentTextRadius;
percentTextRectF.top = centerY - percentTextRadius;
percentTextRectF.right = centerX + percentTextRadius;
percentTextRectF.bottom = centerY + percentTextRadius;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//繪制進度框的背景
canvas.drawArc(progressRectF, 0, 360, false, progressBackPaint);
//繪制進度框的前景(從圓形最高點中間针饥,順時針繪制)
canvas.drawArc(progressRectF, -90, percentProgress / 100.0f * 360, false, progressFrontPaint);
//百分比文字
String text = percentProgress + "%";
//計算百分比文字的弧跨度
float sweepAngle = (float) (percentTextPaint.measureText(text) * 360 / (2 * Math.PI * percentTextRadius));
//初始化百分比文字的弧路徑
percentTextPath.addArc(percentTextRectF, percentProgress * 3.6f - 90.0f - sweepAngle / 2.0f, sweepAngle);
//繪制弧形百分比文字
canvas.drawTextOnPath(text, percentTextPath, 0, 0, percentTextPaint);
//路徑重置
percentTextPath.reset();
}
/**
* 設置當前百分比進度
*/
public void setPercentProgress(int percentProgress) {
this.percentProgress = percentProgress;
invalidate();
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PercentProgressBar">
<attr name="progressWidth" format="dimension"/><!--進度條寬度-->
<attr name="progressBackColor" format="color"/><!--進度條背景色-->
<attr name="progressFrontColor" format="color"/><!--進度條前景色-->
<attr name="percentTextSize" format="dimension"/><!--百分比文字的大小-->
<attr name="percentTextColor" format="color"/><!--百分比文字的顏色-->
</declare-styleable>
</resources>
在布局文件dialog_layout.xml中使用如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.feng.edward.percentprogressbardemo1.view.PercentProgressBar
android:id="@+id/circle_percent_view"
android:layout_width="120dp"
android:layout_height="150dp"
android:focusable="true"
android:clickable="true"
android:layout_gravity="center"
app:percentTextSize="10sp"
app:percentTextColor="#ff0000"
app:progressFrontColor="@color/colorPrimary"
app:progressWidth="2dp"
/>
<com.feng.edward.percentprogressbardemo1.view.CircleImageView
android:id="@+id/circle_image_view"
android:layout_width="70dp"
android:layout_height="70dp"
android:alpha="0"
android:layout_gravity="center"
android:src="@mipmap/jianshu_logo"/>
</FrameLayout>
如果想了解CircleImageView,請訪問上篇文章史上最簡潔高效的圓形ImageView
自定義進度條彈出框ProgressDialog需频,代碼如下:
package com.feng.edward.percentprogressbardemo1.dialog;
import com.feng.edward.percentprogressbardemo1.R;
import com.feng.edward.percentprogressbardemo1.view.CircleImageView;
import com.feng.edward.percentprogressbardemo1.view.PercentProgressBar;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
/**
* 功能描述:
*
* @author (作者) edward(馮豐楓)
* @link http://www.reibang.com/u/f7176d6d53d2
* 創(chuàng)建時間: 2018/4/17 0017
*/
public class ProgressDialog {
private final Dialog mDialog;
private final PercentProgressBar mPercentProgress;
private final CircleImageView mCircleImageView;
public ProgressDialog(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
mPercentProgress = view.findViewById(R.id.circle_percent_view);
mCircleImageView = view.findViewById(R.id.circle_image_view);
mDialog = new Dialog(context, R.style.ProgressDialogTheme);
mDialog.setContentView(view);
mDialog.setCanceledOnTouchOutside(true);
}
public void show() {
mDialog.show();
}
public void setPercentProgress(int percentProgress) {
mPercentProgress.setPercentProgress(percentProgress);
mCircleImageView.setAlpha((float) percentProgress / 100);
}
public void dismiss() {
mDialog.dismiss();
}
}
在MainActivity中使用如下:
package com.feng.edward.percentprogressbardemo1;
import com.feng.edward.percentprogressbardemo1.dialog.ProgressDialog;
import com.feng.edward.percentprogressbardemo1.util.IPublishProgress;
import com.feng.edward.percentprogressbardemo1.util.MyAsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements MyAsyncTask.IIsViewActive {
private ProgressDialog mProgressDialog;
private TextView mainText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressDialog = new ProgressDialog(this);
mainText = findViewById(R.id.main_text);
mainText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mainText.setText(R.string.downloading);
downLoad();
}
});
}
private void downLoad() {
MyAsyncTask.<Void, Integer, Void>newBuilder()
.setPreExecute(new MyAsyncTask.IPreExecute() {
@Override
public void onPreExecute() {
mProgressDialog.show();
}
})
.setDoInBackground(new MyAsyncTask.IDoInBackground<Void, Integer, Void>() {
@Override
public Void doInBackground(IPublishProgress<Integer> publishProgress, Void... voids) {
try {
for (int i = 0; i <= 100; i++) {
Thread.sleep(100);
publishProgress.showProgress(i);
}
} catch (Exception ignore) {
}
return null;
}
})
.setProgressUpdate(new MyAsyncTask.IProgressUpdate<Integer>() {
@Override
public void onProgressUpdate(Integer... values) {
mProgressDialog.setPercentProgress(values[0]);
}
})
.setViewActive(this)
.setPostExecute(new MyAsyncTask.IPostExecute<Void>() {
@Override
public void onPostExecute(Void aVoid) {
mProgressDialog.dismiss();
mainText.setText(R.string.download_finish);
}
})
.start();
}
@Override
public boolean isViewActive() {
return !(isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed()));
}
}
如想了解MyAsyncTask丁眼,請訪問Android AsyncTask 優(yōu)化封裝
activity_mian.xml中的代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_text"
android:layout_centerInParent="true"/>
</RelativeLayout>
在布局文件中,設置百分比文字大小percentTextSize和進度條寬度progressWidth昭殉,可呈現(xiàn)以下兩種不同的效果:
對應屬性為:
app:percentTextSize="10sp"
app:percentTextColor="#ff0000"
app:progressWidth="12dp"
app:progressFrontColor="#3F51B5"
app:progressBackColor="#ffffff"
對應屬性為:
app:percentTextSize="10sp"
app:percentTextColor="#ff0000"
app:progressWidth="2dp"
app:progressFrontColor="#3F51B5"
app:progressBackColor="#ffffff"