android實(shí)現(xiàn)圓形漸變進(jìn)度條
最近項(xiàng)目中使用到了漸變效果的圓形進(jìn)度條,網(wǎng)上找了很多漸變效果不夠圓滑,兩個(gè)漸變顏色之間有明顯的過渡,或者有些代碼畫出來的效果過渡不美觀,于是自己參照寫了一個(gè),喜歡的朋友可以參考或者直接使用。
先上一張效果圖,視頻錄制不太好,不過不影響效果
下面開始介紹實(shí)現(xiàn)代碼,比較簡單,直接貼代碼吧
1、聲明自定義屬性
在項(xiàng)目的valuse文件夾下新建attrs.xml,在里面定義自定義控件需要的屬性
<declare-styleable name="RoundProgress"> <attr name="bgColor" format="color" /> <attr name="roundWidth" format="dimension" /> <attr name="textColor" format="color" /> <attr name="textSize" format="dimension" /> <attr name="maxProgress" format="integer" /> <attr name="textIsDisplayable" format="boolean" /> <attr name="lineColor" format="color" /> </declare-styleable>
2、自定義一個(gè)進(jìn)度條RoundProgres繼承view類
package com.blankj.progressring; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SweepGradient; import android.graphics.Typeface; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.animation.LinearInterpolator; import org.jetbrains.annotations.Nullable; /** * 類描述:漸變的圓形進(jìn)度條 * * @author:lusy * @date :2018/10/17 */ public class RoundProgress extends View { private static final String TAG = "roundProgress"; /** * 背景圓環(huán)畫筆 */ private Paint bgPaint; /** * 白色標(biāo)記畫筆 */ private Paint iconPaint; /** * 進(jìn)度畫筆 */ private Paint progressPaint; /** * 進(jìn)度文本畫筆 */ private Paint textPaint; /** * 背景圓環(huán)的顏色 */ private int bgColor; /** * 線條進(jìn)度的顏色 */ private int iconColor; private int[] progressColor; /** * 中間進(jìn)度百分比的字符串的顏色 */ private int textColor; /** * 中間進(jìn)度百分比的字符串的字體大小 */ private float textSize; /** * 圓環(huán)的寬度 */ private float roundWidth; /** * 最大進(jìn)度 */ private int max; /** * 當(dāng)前進(jìn)度 */ private float progress; /** * 是否顯示中間的進(jìn)度 */ private boolean textIsDisplayable; /** * 圓環(huán)半徑 */ private int mRadius; private int center; private float startAngle = -90; private float currentAngle; private float currentProgress; public RoundProgress(Context context) { this(context, null); } public RoundProgress(Context context, @Nullable AttributeSet attrs) { super(context, attrs); TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgress); //獲取自定義屬性和默認(rèn)值 bgColor = mTypedArray.getColor(R.styleable.RoundProgress_bgColor, Color.parseColor("#2d2d2d")); iconColor = mTypedArray.getColor(R.styleable.RoundProgress_lineColor, Color.parseColor("#ffffff")); textColor = mTypedArray.getColor(R.styleable.RoundProgress_textColor, Color.parseColor("#ffffff")); textSize = mTypedArray.getDimension(R.styleable.RoundProgress_textSize, 15); roundWidth = mTypedArray.getDimension(R.styleable.RoundProgress_roundWidth, 5); max = mTypedArray.getInteger(R.styleable.RoundProgress_maxProgress, 100); textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgress_textIsDisplayable, true); progressColor = new int[]{Color.parseColor("#747eff"), Color.parseColor("#0018ff"), Color.TRANSPARENT}; mTypedArray.recycle(); initPaint(); } public RoundProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //測量控件應(yīng)占的寬高大小,此處非必需,只是為了確保布局中設(shè)置的寬高不一致時(shí)仍顯示完整的圓 int measureWidth = MeasureSpec.getSize(widthMeasureSpec); int measureHeight = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(Math.min(measureWidth, measureHeight), Math.min(measureWidth, measureHeight)); } private void initPaint() { bgPaint = new Paint(); bgPaint.setStyle(Paint.Style.STROKE); bgPaint.setAntiAlias(true); bgPaint.setColor(bgColor); bgPaint.setStrokeWidth(roundWidth); iconPaint = new Paint(); iconPaint.setStyle(Paint.Style.STROKE); iconPaint.setAntiAlias(true); iconPaint.setColor(iconColor); iconPaint.setStrokeWidth(roundWidth); progressPaint = new Paint(); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setAntiAlias(true); progressPaint.setStrokeWidth(roundWidth); textPaint = new Paint(); textPaint.setStyle(Paint.Style.STROKE); textPaint.setTypeface(Typeface.DEFAULT_BOLD); textPaint.setAntiAlias(true); textPaint.setColor(textColor); textPaint.setTextSize(textSize); textPaint.setStrokeWidth(0); } @Override protected void onDraw(Canvas canvas) { /** * 畫最外層的大圓環(huán) */ //獲取圓心的x坐標(biāo) center = Math.min(getWidth(), getHeight()) / 2; // 圓環(huán)的半徑 mRadius = (int) (center - roundWidth / 2); RectF oval = new RectF(center - mRadius, center - mRadius, center + mRadius, center + mRadius); //畫背景圓環(huán) canvas.drawArc(oval, startAngle, 360, false, bgPaint); //畫進(jìn)度圓環(huán) drawProgress(canvas, oval); canvas.drawArc(oval, startAngle, currentAngle, false, progressPaint); //畫白色圓環(huán) float start = startAngle + currentAngle - 1; canvas.drawArc(oval, start, 3, false, iconPaint); //百分比文字 int percent = (int) (((float) progress / (float) max) * 100); //測量字體寬度,我們需要根據(jù)字體的寬度設(shè)置在圓環(huán)中間 String text = String.valueOf(percent)+"%"; Rect textRect = new Rect(); textPaint.getTextBounds(text, 0, text.length(), textRect); if (textIsDisplayable && percent >= 0) { //畫出進(jìn)度百分比文字 float x = (getWidth() - textRect.width()) / 2; float y = (getHeight() + textRect.height()) / 2; canvas.drawText(text, x, y, textPaint); } if (currentProgress < progress) { currentProgress++; postInvalidate(); } } /** * 畫進(jìn)度圓環(huán) * * @param canvas * @param oval */ private void drawProgress(Canvas canvas, RectF oval) { float section = progress / 100; currentAngle = section * 360; //把需要繪制的角度分成100等分 float unitAngle = (float) (currentAngle / 100.0); for (float i = 0, end = currentProgress * unitAngle; i <= end; i++) { SweepGradient shader = new SweepGradient(center, center, progressColor, new float[]{0.0f, section, 1.0f}); Matrix matrix = new Matrix(); matrix.setRotate(startAngle, center, center); shader.setLocalMatrix(matrix); progressPaint.setShader(shader); canvas.drawArc(oval, startAngle + i, 1, false, progressPaint); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //計(jì)算外圓半徑 寬,高最小值-填充邊距/2 center = (Math.min(w, h)) / 2; mRadius = (int) ((Math.min(w, h)) - roundWidth / 2); } public int getMax() { return max; } /** * 設(shè)置進(jìn)度的最大值 * * @param max */ public void setMax(int max) { if (max < 0) { Log.e(TAG, "max progress not allow <0"); return; } this.max = max; } /** * 獲取進(jìn)度 * * @return */ public float getProgress() { return progress; } /** * 設(shè)置進(jìn)度 * * @param progressValue * @param useAnima 是否需要?jiǎng)赢? */ public void setProgress(float progressValue, boolean useAnima) { float percent = progressValue * max / 100; if (percent < 0) { percent = 0; } if (percent > 100) { percent = 100; } //使用動(dòng)畫 if (useAnima) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, percent); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { progress = (float) animation.getAnimatedValue(); postInvalidate(); } }); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setDuration(1500); valueAnimator.start(); } else { this.progress = percent; postInvalidate(); } } public int getTextColor() { return textColor; } public void setTextColor(int textColor) { this.textColor = textColor; } public float getTextSize() { return textSize; } public void setTextSize(float textSize) { this.textSize = textSize; } public float getRoundWidth() { return roundWidth; } public void setRoundWidth(float roundWidth) { this.roundWidth = roundWidth; } public int[] getProgressColor() { return progressColor; } public void setProgressColor(int[] progressColor) { this.progressColor = progressColor; postInvalidate(); } public int getBgColor() { return bgColor; } public void setBgColor(int bgColor) { this.bgColor = bgColor; } public int getIconColor() { return iconColor; } public void setIconColor(int iconColor) { this.iconColor = iconColor; } public boolean isTextIsDisplayable() { return textIsDisplayable; } public void setTextIsDisplayable(boolean textIsDisplayable) { this.textIsDisplayable = textIsDisplayable; } public int getmRadius() { return mRadius; } public void setmRadius(int mRadius) { this.mRadius = mRadius; } public int getCenter() { return center; } public void setCenter(int center) { this.center = center; } public float getStartAngle() { return startAngle; } public void setStartAngle(float startAngle) { this.startAngle = startAngle; } }
3、使用自定義進(jìn)度條view
activity布局文件使用如下,為了方便測試效果,新增進(jìn)度加、進(jìn)度減,修改進(jìn)度條顏色的按鈕
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#242424" android:gravity="center"> <LinearLayout android:id="@+id/buttonLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:gravity="center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/addProgress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="進(jìn)度+" /> <Button android:id="@+id/changeColor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="設(shè)置顏色" /> <Button android:id="@+id/subtraceProgress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="進(jìn)度-" /> </LinearLayout> <com.blankj.progressring.RoundProgress android:id="@+id/socProgress" android:layout_width="70dp" android:layout_height="70dp" android:layout_below="@id/buttonLayout" android:layout_centerHorizontal="true" android:layout_gravity="center" android:layout_marginLeft="20dp" android:layout_marginBottom="2dp" app:bgColor="@color/bgColor" app:maxProgress="100" app:roundWidth="8dp" app:textIsDisplayable="true" app:textSize="18sp" /> </RelativeLayout>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁源碼查看器實(shí)例
這篇文章主要介紹了Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁源碼查看器,結(jié)合實(shí)例形式分析了Android針對網(wǎng)絡(luò)圖片及網(wǎng)頁的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-01-01快速解決android webview https圖片不顯示的問題
今天小編就為大家分享一篇快速解決android webview https圖片不顯示的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Android實(shí)現(xiàn)為ListView同時(shí)設(shè)置點(diǎn)擊時(shí)的背景和點(diǎn)擊松手之后的背景
這篇文章主要介紹了Android實(shí)現(xiàn)為ListView同時(shí)設(shè)置點(diǎn)擊時(shí)的背景和點(diǎn)擊松手之后的背景,以實(shí)例形式較為詳細(xì)的分析了界面元素與功能的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02三行Android代碼實(shí)現(xiàn)白天夜間模式流暢切換
這篇文章主要為大家分享了三行Android代碼實(shí)現(xiàn)白天夜間模式流暢切換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Android與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本
這篇文章主要為大家介紹了安卓與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09android中Glide實(shí)現(xiàn)加載圖片保存至本地并加載回調(diào)監(jiān)聽
本篇文章主要介紹了android中Glide實(shí)現(xiàn)加載圖片保存至本地并加載回調(diào)監(jiān)聽,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09Android View移動(dòng)的3種方式總結(jié)
這篇文章主要給大家介紹了Android View移動(dòng)的三種方式,在介紹這三種方式之前先介紹了Android坐標(biāo)系的定義規(guī)則以及View的一些位置參數(shù)。有需要的朋友們可以參考借鑒。2016-09-09Android應(yīng)用開發(fā)之簡易、大氣音樂播放器實(shí)現(xiàn)專輯倒影效果
這篇文章主要介紹了Android應(yīng)用開發(fā)之簡單、大氣音樂播放器實(shí)現(xiàn)專輯倒影效果,對android音樂播放器感興趣的朋友可以參考下2015-10-10