Android模擬實(shí)現(xiàn)華為系統(tǒng)升級(jí)進(jìn)度條
前言
之前用華為Android系統(tǒng)的時(shí)候總是會(huì)想到這種虛線進(jìn)度條是怎么實(shí)現(xiàn)的,因?yàn)橹苯佑胏anvas的drawArc方法畫出來的是實(shí)線,所以最近在網(wǎng)上搜了很多進(jìn)度條相關(guān)的文章,也了解到了其中的原理,下面分享給大家。下面這兩篇文章是我之前寫的Android進(jìn)度條相關(guān)的文章,有興趣的朋友們可以看看:
Android實(shí)現(xiàn)絢麗的自定義進(jìn)度條
詳解Android如何自定義view實(shí)現(xiàn)圓形進(jìn)度條
下面開始講解虛線進(jìn)度條的實(shí)現(xiàn)方法,首先看一張圖:

實(shí)現(xiàn)步驟
大家可以先想想這種進(jìn)度條是怎么實(shí)現(xiàn)的?網(wǎng)上有各種各樣的方法,也有人用path的lineTo()方法實(shí)現(xiàn)了類似的效果。但是我個(gè)人覺得canvas的drawArc方法也是個(gè)不錯(cuò)的選擇,適合自己的才是最好的。
canvas.drawArc(rectF, 0, process, false, mPaint);
閱讀了大量文章,最后發(fā)現(xiàn)改變paint的樣式是最簡單好用的方法。給paint設(shè)置一個(gè)effect就好了。
1.用DashPathEffect給paint加上虛線效果
DashPathEffect dashPathEffect = new DashPathEffect(new float[]{8, 6}, 0);
mPaintBack.setPathEffect(dashPathEffect);
build一下項(xiàng)目,看到的結(jié)果是這樣的:

能實(shí)現(xiàn)這個(gè)效果就大功告成了,如果看過我前面兩篇文章的朋友們就知道,后面的步驟就簡單了,加個(gè)進(jìn)度條和動(dòng)畫效果就可以了。
private void drawBack(Canvas canvas) {
RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth);
PathEffect effects = new DashPathEffect(new float[]{8, 6}, 0);
mPaintBack.setPathEffect(effects);
canvas.drawArc(rectF, 0, 360, false, mPaintBack);
}
2.畫出進(jìn)度條
畫進(jìn)度條和畫背景完全一樣,只是畫筆顏色和小點(diǎn)個(gè)數(shù)不一樣。

代碼如下:
private void drawProgress(Canvas canvas) {
RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth);
PathEffect effects = new DashPathEffect(new float[]{8, 6}, 0);
mPaint.setPathEffect(effects);
canvas.drawArc(rectF, 0, process, false, mPaint);
}
3.繪制文字
接下來是繪制文字,實(shí)現(xiàn)文字居中的效果。思路是計(jì)算出圓心,調(diào)用canvas.drawText的方法就能在canvas上面繪制文字了。這里不需要更新進(jìn)度文字,所以就更省事了。

EMUI 下面的10.0.0也是一樣的方法,只是給Y坐標(biāo)加一下55,往下移一點(diǎn)就好。
//繪制文字
private void drawText(Canvas canvas) {
int mTxtWidth = getTextWidth();
int mTxtHeight = getTextHeight();
int x = getWidth() / 2 - mTxtWidth / 2;
int y = getHeight() / 2 + mTxtHeight / 4;
canvas.drawText(getResources().getString(R.string.defaultTextEmui), x, y, mPaintText);
}
//繪制下方文字
private void drawTextBlow(Canvas canvas) {
int mTxtWidth = getTextWidthBlow();
int mTxtHeight = getTextHeight();
int x = getWidth() / 2 - mTxtWidth / 2;
int y = getHeight() / 2 + mTxtHeight / 4 + 55;
canvas.drawText(getResources().getString(R.string.defaultTextBelow), x, y, mPaintTextLevel);
}
4.加入動(dòng)畫效果
/**
* 設(shè)置動(dòng)畫效果
*/
public void start() {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 360);
valueAnimator.setDuration(duration);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(animation -> {
process = (int) animation.getAnimatedValue();
invalidate();
});
valueAnimator.start();
}
最終效果:

完整代碼
package com.example.floatingwindow.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
import com.example.floatingwindow.R;
public class DottedLineProgressBar extends View {
private Paint mPaint;
private Paint mPaintBack;
private Paint mPaintText;
private Paint mPaintTextLevel;
private int strokeWidth = 30;
private int textSize = 22;
private int textSizeBlow = 15;
private long duration = 3500;
private int process;
public DottedLineProgressBar(Context context) {
super(context);
init();
}
public DottedLineProgressBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DottedLineProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setStrokeWidth(int width) {
strokeWidth = width;
}
public void setTextSize(int textSize) {
this.textSize = textSize;
}
public void setDuration(long duration) {
this.duration = duration;
}
public void setTextSizeBlow(int textSizeBlow) {
this.textSizeBlow = textSizeBlow;
}
//初始化畫筆
private void init() {
mPaintBack = new Paint();//圓角矩形
mPaintBack.setColor(getResources().getColor(R.color.gray));//圓角矩形顏色
mPaintBack.setAntiAlias(true);// 抗鋸齒效果
mPaintBack.setStyle(Paint.Style.STROKE);//設(shè)置畫筆樣式
mPaintBack.setStrokeWidth(strokeWidth);//設(shè)置畫筆寬度
mPaint = new Paint();
mPaint.setColor(getResources().getColor(R.color.blue));
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(strokeWidth);
mPaintText = new Paint();
mPaintText.setAntiAlias(true);
mPaintText.setStyle(Paint.Style.FILL);
mPaintText.setColor(getResources().getColor(R.color.blue));
mPaintText.setTextSize(sp2px(textSize));
mPaintTextLevel = new Paint();
mPaintTextLevel.setAntiAlias(true);
mPaintTextLevel.setStyle(Paint.Style.FILL);
mPaintTextLevel.setColor(getResources().getColor(R.color.gray));
mPaintTextLevel.setTextSize(sp2px(textSizeBlow));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBack(canvas);
drawProgress(canvas);
drawText(canvas);
drawTextBlow(canvas);
}
private void drawBack(Canvas canvas) {
RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth);
PathEffect effects = new DashPathEffect(new float[]{8, 6}, 0);
mPaintBack.setPathEffect(effects);
canvas.drawArc(rectF, 0, 360, false, mPaintBack);
}
private void drawProgress(Canvas canvas) {
RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth);
PathEffect effects = new DashPathEffect(new float[]{8, 6}, 0);
mPaint.setPathEffect(effects);
canvas.drawArc(rectF, 0, process, false, mPaint);
}
//繪制文字
private void drawText(Canvas canvas) {
int mTxtWidth = getTextWidth();
int mTxtHeight = getTextHeight();
int x = getWidth() / 2 - mTxtWidth / 2;
int y = getHeight() / 2 + mTxtHeight / 4;
canvas.drawText(getResources().getString(R.string.defaultTextEmui), x, y, mPaintText);
}
//繪制下方文字
private void drawTextBlow(Canvas canvas) {
int mTxtWidth = getTextWidthBlow();
int mTxtHeight = getTextHeight();
int x = getWidth() / 2 - mTxtWidth / 2;
int y = getHeight() / 2 + mTxtHeight / 4 + 55;
canvas.drawText(getResources().getString(R.string.defaultTextBelow), x, y, mPaintTextLevel);
}
private int getTextWidth() {
String text = getResources().getString(R.string.defaultTextEmui);
return (int) mPaintText.measureText(text, 0, text.length());
}
private int getTextWidthBlow() {
String text = getResources().getString(R.string.defaultTextBelow);
return (int) mPaintTextLevel.measureText(text, 0, text.length());
}
private int getTextHeight() {
Paint.FontMetrics fm = mPaintText.getFontMetrics();
return (int) Math.ceil(fm.descent - fm.ascent);
}
private int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
getResources().getDisplayMetrics());
}
/**
* 設(shè)置動(dòng)畫效果
*/
public void start() {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 360);
valueAnimator.setDuration(duration);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(animation -> {
process = (int) animation.getAnimatedValue();
invalidate();
});
valueAnimator.start();
}
}
kotlin調(diào)用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
dottedLineProgressBar.post {
dottedLineProgressBar.start()
}
}
}
XML:
<com.example.floatingwindow.widget.DottedLineProgressBar
android:id="@+id/dottedLineProgressBar"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center">
</com.example.floatingwindow.widget.DottedLineProgressBar>
以上就是完整的實(shí)現(xiàn)過程了。
項(xiàng)目源碼:https://gitee.com/tu_erhongjiang/android-progress-bar
到此這篇關(guān)于Android模擬實(shí)現(xiàn)華為系統(tǒng)升級(jí)進(jìn)度條的文章就介紹到這了,更多相關(guān)Android進(jìn)度條內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android原生TabLayout使用的超全解析(看這篇就夠了)
現(xiàn)在很多app都有頂部可左右切換的導(dǎo)航欄,并且還帶動(dòng)畫效果,要實(shí)現(xiàn)這種導(dǎo)航欄,可以使用Android原生的Tablayout也可以借助第三方框架實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于Android原生TabLayout使用的相關(guān)資料,需要的朋友可以參考下2022-09-09
Flutter路由傳遞參數(shù)及解析實(shí)現(xiàn)
這篇文章介紹了Flutter路由傳遞參數(shù)及解析實(shí)現(xiàn)的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11
Android 截取手機(jī)屏幕兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android 截取手機(jī)屏幕兩種實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2017-05-05
android實(shí)現(xiàn)ViewPager的Indicator的實(shí)例代碼
本篇文章主要介紹了android實(shí)現(xiàn)ViewPager的Indicator的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02
Android開發(fā)之創(chuàng)建可點(diǎn)擊的Button實(shí)現(xiàn)方法
這篇文章主要介紹了Android創(chuàng)建可點(diǎn)擊的Button實(shí)現(xiàn)方法,實(shí)例分析了Android創(chuàng)建button按鈕過程中的界面配置,功能實(shí)現(xiàn)與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-03-03
Android通過startService實(shí)現(xiàn)文件批量下載
這篇文章主要為大家詳細(xì)介紹了Android通過startService實(shí)現(xiàn)文件批量下載的示例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-12-12
android尺子的自定義view——RulerView詳解
這篇文章主要介紹了android尺子的自定義view——RulerView詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
android中DownloadManager實(shí)現(xiàn)版本更新,監(jiān)聽下載進(jìn)度實(shí)例
本篇文章主要介紹了android中DownloadManager實(shí)現(xiàn)版本更新,監(jiān)聽下載進(jìn)度實(shí)例。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03
Android 混合動(dòng)畫詳解及實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 混合動(dòng)畫詳解及實(shí)現(xiàn)代碼的相關(guān)資料,簡單的一種動(dòng)畫(如旋轉(zhuǎn)、縮放、漸變、位移等)有時(shí)候并不能滿足我們項(xiàng)目的要求,這時(shí)候就需要運(yùn)用到混合動(dòng)畫,需要的朋友可以參考下2016-11-11
ffmpeg實(shí)現(xiàn)去水印以及切分視頻demo
這篇文章主要為大家介紹了ffmpeg實(shí)現(xiàn)去水印以及切分視頻demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11

