Android繪制圓形百分比加載圈效果
先看一組加載效果圖,有點粉粉的加載圈:

自定義這樣的圓形加載圈還是比較簡單的,主要是用到Canvans的繪制文本,繪制圓和繪制圓弧的api:
/**
* 繪制圓
* @param cx 圓心x坐標
* @param cy 圓心y坐標
* @param radius 圓的半徑
* @param paint 畫筆
*/
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
...
}
/**
* 繪制圓弧
* @param oval 決定圓弧范圍的矩形區(qū)域
* @param startAngle 開始角度
* @param sweepAngle 繪制的角度
* @param useCenter 是否需要連接圓心,true連接,false不連接
* @param paint 畫筆
*/
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint) {
...
}
/**
* 繪制文本
* @param text 需要繪制的字符串
* @param x 繪制文本起點x坐標,注意文本比較特殊,它的起點是左下角的x坐標
* @param y 繪制文本起點y坐標,同樣是左下角的y坐標
* @param paint 畫筆
*/
public void drawText(String text, float x, float y, Paint paint) {
...
}
開始繪圖前需要考慮的以下幾點:
1.獲取控件的寬和高,這個是決定圓的半徑大小的,半徑大小等于寬高的最小值的1/2,為什么是最小值呢?因為這樣就不會受布局文件中寬高屬性不一樣的影響,當然我們自己在使用的時候肯定是寬高都是會寫成一樣的,這樣就剛好是一個正方形,繪制出來的圓就剛好在該正方形區(qū)域內.做了這樣的處理,其他人在用的時候就不用當心圓會不會超出控件范圍的情況了.
2.確定圓心的坐標,有了半徑和圓心坐標就可以確定一個圓了,布局中的控件區(qū)域其實都是一個矩形區(qū)域,如果想要繪制出來的圓剛好處于控件的矩形區(qū)域內并且和矩形的最短的那條邊相切,那么圓心坐標的就是該矩形寬高的1/2,即剛好位于矩形區(qū)域的中心點.
3.繪制圓弧,注意這里的圓弧指的是進度圈,看上面的示例圖是有2種樣式,分別是實心的加載圈和空心加載圈,這個其實就是paint的樣式決定,如果是實心圓,paint設置為Paint.Style.FILL(填充模式),同時drawArc的useCenter設置為true;如果是空心圓則paint設置為Paint.Style.STROKE(線性模式),同時drawArc的useCenter設置為false即可.值得一提的是繪制空心圓的時候還需要考慮圓弧的寬度,寬度有多大將決定進度圈的厚度.因此在定義空心圓的矩形區(qū)域的時候需要減去進度圈的厚度,否則畫出來的進度圈會超出控件的區(qū)域.
4.繪制文本,需要定位起始點,文本的起始點比較特殊,它是以左下角為起始點的,起點x坐標=圓心x坐標-文本寬度1/2;起始點y坐標=圓心y坐標+文本高度1/2;至于文本的寬高獲取可以通過paint的getTextBounds()方法獲取,具體等下看代碼.
ok,直接上代碼,注釋已經很詳細了.
圓形加載圈
public class CircleProgressView extends View {
private int width;//控件寬度
private int height;//控件高
private float radius;//半徑
private float pointX;//圓心x坐標
private float pointY;//圓心y坐標
private int circleBackgroundColor;//背景顏色
private int circleBackgroundAlpha; //背景透明度
private int circleRingColor;//進度顏色
private int progressTextColor;//進度文本的顏色
private int progressTextSize;//進度文本的字體大小
private int circleRingWidth; //進度的寬度
private Paint mPaint;
private int progress;//進度值
private boolean isRingStyle;//是否是空心的圓環(huán)進度樣式
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
circleBackgroundColor = Color.WHITE;
circleRingColor = Color.parseColor("#3A91FF");
progressTextColor = Color.BLACK;
circleBackgroundAlpha = 128;
progressTextSize = 32;
circleRingWidth = 10;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
radius = Math.min(width, height) / 2.0f;
pointX = width / 2.0f;
pointY = height / 2.0f;
}
@Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas);
drawCircleRing(canvas);
drawProgressText(canvas);
}
/**
* 繪制背景色
*
* @param canvas
*/
private void drawBackground(Canvas canvas) {
mPaint.setColor(circleBackgroundColor);
mPaint.setAlpha(circleBackgroundAlpha);
canvas.drawCircle(pointX, pointY, radius, mPaint);
}
/**
* 繪制圓環(huán)
*
* @param canvas
*/
private void drawCircleRing(Canvas canvas) {
mPaint.setColor(circleRingColor);
RectF oval = new RectF();
if (isRingStyle) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(circleRingWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);
//注意:定義圓環(huán)的矩形區(qū)域是需要考慮圓環(huán)的寬度
oval.left = circleRingWidth / 2.0f;
oval.top = height / 2.0f - radius + circleRingWidth / 2.0f;
oval.right = 2 * radius - circleRingWidth / 2.0f;
oval.bottom = height / 2.0f + radius - circleRingWidth / 2.0f;
canvas.drawArc(oval, 0, 360 * progress / 100, false, mPaint);
} else {
mPaint.setStyle(Paint.Style.FILL);
oval.left = 0;
oval.top = height / 2.0f - radius;
oval.right = 2 * radius;
oval.bottom = height / 2.0f + radius;
canvas.drawArc(oval, 0, 360 * progress / 100, true, mPaint);
}
}
/**
* 繪制進度文本
*
* @param canvas
*/
private void drawProgressText(Canvas canvas) {
mPaint.setColor(progressTextColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(progressTextSize);
Rect textBound = new Rect();
String text = progress + "%";
//獲取文本的矩形區(qū)域到textBound中
mPaint.getTextBounds(text, 0, text.length(), textBound);
int textWidth = textBound.width();
int textHeight = textBound.height();
float x = pointX - textWidth / 2.0f;
float y = pointY + textHeight / 2.0f;
canvas.drawText(text, x, y, mPaint);
}
/**
* 更新進度
*
* @param progress
*/
public void setValue(int progress) {
this.progress = progress;
invalidate();
}
/**
* 設置進度圓環(huán)的樣式
*
* @param isRing true是空心的圓環(huán),false表示實心的圓環(huán)
*/
public void setCircleRingStyle(boolean isRing) {
this.isRingStyle = isRing;
}
/**
* 設置背景透明度
*
* @param alpha 0~255
*/
public void setCircleBackgroundAlpha(int alpha) {
this.circleBackgroundAlpha = alpha;
}
/**
* 設置進度文本的大小
* @param progressTextSize
*/
public void setProgressTextSize(int progressTextSize) {
this.progressTextSize = progressTextSize;
}
/**
* 設置進度文本的顏色
* @param progressTextColor
*/
public void setProgressTextColor(int progressTextColor) {
this.progressTextColor = progressTextColor;
}
}
測試類
public class MainActivity extends AppCompatActivity {
private CircleProgressView mCircleProgressView;
private int progress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCircleProgressView = (CircleProgressView) findViewById(R.id.progressView);
mCircleProgressView.setCircleRingStyle(false);//實心圓
HandlerThread thread = new HandlerThread("draw-thread");
thread.start();
Handler tHandler = new Handler(thread.getLooper()) {
@Override
public void handleMessage(Message msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mCircleProgressView.setValue(progress++);
}
});
if (progress <100) {
sendEmptyMessageDelayed(0, 100);
}
}
};
tHandler.sendEmptyMessage(0);
}
}
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:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorAccent" tools:context="mchenys.net.csdn.blog.progressview.MainActivity"> <mchenys.net.csdn.blog.progressview.CircleProgressView android:id="@+id/progressView" android:layout_width="100dp" android:layout_height="200dp" android:layout_centerInParent="true" /> </RelativeLayout>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android SharedPreferences實現(xiàn)記住密碼和自動登錄
這篇文章主要為大家詳細介紹了Android SharedPreferences實現(xiàn)記住密碼和自動登錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-05-05
Android android:exported = true 用法詳解
在本篇文章里小編給大家整理了關于Android android:exported = true 用法,需要的朋友們參考下。2019-09-09
Android9.0 SystemUI 網絡信號欄定制修改的流程解析
這篇文章主要介紹了Android9.0 SystemUI 網絡信號欄定制修改的流程,本文通過圖文實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11
Android Zygote啟動構造流程及進程創(chuàng)建詳解
這篇文章主要為大家介紹了Android Zygote啟動構造流程及進程創(chuàng)建詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
Android手機通過rtp發(fā)送aac數(shù)據(jù)給vlc播放的實現(xiàn)步驟
這篇文章主要介紹了Android手機通過rtp發(fā)送aac數(shù)據(jù)給vlc播放的實現(xiàn)步驟,幫助大家更好的理解和學習使用Android,感興趣的朋友可以了解下2021-04-04
Android 實現(xiàn)按兩次返回鍵退出程序(兩種方法)
這篇文章主要介紹了Android 實現(xiàn)按兩次返回鍵退出程序(兩種方法)的相關資料,這里不僅實現(xiàn)還對原理進行了分析,需要的朋友可以參考下2017-07-07

