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

自定義這樣的圓形加載圈還是比較簡單的,主要是用到Canvans的繪制文本,繪制圓和繪制圓弧的api:
/**
* 繪制圓
* @param cx 圓心x坐標(biāo)
* @param cy 圓心y坐標(biāo)
* @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 繪制文本起點(diǎn)x坐標(biāo),注意文本比較特殊,它的起點(diǎn)是左下角的x坐標(biāo)
* @param y 繪制文本起點(diǎn)y坐標(biāo),同樣是左下角的y坐標(biāo)
* @param paint 畫筆
*/
public void drawText(String text, float x, float y, Paint paint) {
...
}
開始繪圖前需要考慮的以下幾點(diǎn):
1.獲取控件的寬和高,這個(gè)是決定圓的半徑大小的,半徑大小等于寬高的最小值的1/2,為什么是最小值呢?因?yàn)檫@樣就不會(huì)受布局文件中寬高屬性不一樣的影響,當(dāng)然我們自己在使用的時(shí)候肯定是寬高都是會(huì)寫成一樣的,這樣就剛好是一個(gè)正方形,繪制出來的圓就剛好在該正方形區(qū)域內(nèi).做了這樣的處理,其他人在用的時(shí)候就不用當(dāng)心圓會(huì)不會(huì)超出控件范圍的情況了.
2.確定圓心的坐標(biāo),有了半徑和圓心坐標(biāo)就可以確定一個(gè)圓了,布局中的控件區(qū)域其實(shí)都是一個(gè)矩形區(qū)域,如果想要繪制出來的圓剛好處于控件的矩形區(qū)域內(nèi)并且和矩形的最短的那條邊相切,那么圓心坐標(biāo)的就是該矩形寬高的1/2,即剛好位于矩形區(qū)域的中心點(diǎn).
3.繪制圓弧,注意這里的圓弧指的是進(jìn)度圈,看上面的示例圖是有2種樣式,分別是實(shí)心的加載圈和空心加載圈,這個(gè)其實(shí)就是paint的樣式?jīng)Q定,如果是實(shí)心圓,paint設(shè)置為Paint.Style.FILL(填充模式),同時(shí)drawArc的useCenter設(shè)置為true;如果是空心圓則paint設(shè)置為Paint.Style.STROKE(線性模式),同時(shí)drawArc的useCenter設(shè)置為false即可.值得一提的是繪制空心圓的時(shí)候還需要考慮圓弧的寬度,寬度有多大將決定進(jìn)度圈的厚度.因此在定義空心圓的矩形區(qū)域的時(shí)候需要減去進(jìn)度圈的厚度,否則畫出來的進(jìn)度圈會(huì)超出控件的區(qū)域.
4.繪制文本,需要定位起始點(diǎn),文本的起始點(diǎn)比較特殊,它是以左下角為起始點(diǎn)的,起點(diǎn)x坐標(biāo)=圓心x坐標(biāo)-文本寬度1/2;起始點(diǎn)y坐標(biāo)=圓心y坐標(biāo)+文本高度1/2;至于文本的寬高獲取可以通過paint的getTextBounds()方法獲取,具體等下看代碼.
ok,直接上代碼,注釋已經(jīng)很詳細(xì)了.
圓形加載圈
public class CircleProgressView extends View {
private int width;//控件寬度
private int height;//控件高
private float radius;//半徑
private float pointX;//圓心x坐標(biāo)
private float pointY;//圓心y坐標(biāo)
private int circleBackgroundColor;//背景顏色
private int circleBackgroundAlpha; //背景透明度
private int circleRingColor;//進(jìn)度顏色
private int progressTextColor;//進(jìn)度文本的顏色
private int progressTextSize;//進(jìn)度文本的字體大小
private int circleRingWidth; //進(jìn)度的寬度
private Paint mPaint;
private int progress;//進(jìn)度值
private boolean isRingStyle;//是否是空心的圓環(huán)進(jì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);
}
}
/**
* 繪制進(jìn)度文本
*
* @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);
}
/**
* 更新進(jìn)度
*
* @param progress
*/
public void setValue(int progress) {
this.progress = progress;
invalidate();
}
/**
* 設(shè)置進(jìn)度圓環(huán)的樣式
*
* @param isRing true是空心的圓環(huán),false表示實(shí)心的圓環(huán)
*/
public void setCircleRingStyle(boolean isRing) {
this.isRingStyle = isRing;
}
/**
* 設(shè)置背景透明度
*
* @param alpha 0~255
*/
public void setCircleBackgroundAlpha(int alpha) {
this.circleBackgroundAlpha = alpha;
}
/**
* 設(shè)置進(jìn)度文本的大小
* @param progressTextSize
*/
public void setProgressTextSize(int progressTextSize) {
this.progressTextSize = progressTextSize;
}
/**
* 設(shè)置進(jìn)度文本的顏色
* @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);//實(shí)心圓
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>
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android?常見獲取設(shè)備標(biāo)識(shí)方法總結(jié)
隨著Android系統(tǒng)版本更新,Google對(duì)用戶隱私保護(hù)增強(qiáng),限制獲取設(shè)備標(biāo)識(shí),文中測試DeviceID、ANDROID_ID、Serial、MAC地址等方法在不同API級(jí)別的表現(xiàn),感興趣的朋友跟隨小編一起看看吧2024-09-09
Android SharedPreferences實(shí)現(xiàn)記住密碼和自動(dòng)登錄
這篇文章主要為大家詳細(xì)介紹了Android SharedPreferences實(shí)現(xiàn)記住密碼和自動(dòng)登錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
Android android:exported = true 用法詳解
在本篇文章里小編給大家整理了關(guān)于Android android:exported = true 用法,需要的朋友們參考下。2019-09-09
Android9.0 SystemUI 網(wǎng)絡(luò)信號(hào)欄定制修改的流程解析
這篇文章主要介紹了Android9.0 SystemUI 網(wǎng)絡(luò)信號(hào)欄定制修改的流程,本文通過圖文實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
Android Zygote啟動(dòng)構(gòu)造流程及進(jìn)程創(chuàng)建詳解
這篇文章主要為大家介紹了Android Zygote啟動(dòng)構(gòu)造流程及進(jìn)程創(chuàng)建詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Android手機(jī)通過rtp發(fā)送aac數(shù)據(jù)給vlc播放的實(shí)現(xiàn)步驟
這篇文章主要介紹了Android手機(jī)通過rtp發(fā)送aac數(shù)據(jù)給vlc播放的實(shí)現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04
Android 實(shí)現(xiàn)按兩次返回鍵退出程序(兩種方法)
這篇文章主要介紹了Android 實(shí)現(xiàn)按兩次返回鍵退出程序(兩種方法)的相關(guān)資料,這里不僅實(shí)現(xiàn)還對(duì)原理進(jìn)行了分析,需要的朋友可以參考下2017-07-07

