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的樣式是最簡(jiǎn)單好用的方法。給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è)效果就大功告成了,如果看過我前面兩篇文章的朋友們就知道,后面的步驟就簡(jiǎn)單了,加個(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 實(shí)現(xiàn)錨點(diǎn)定位思路詳解
本篇文章就使用tablayout、scrollview來實(shí)現(xiàn)android錨點(diǎn)定位的功能。通過<a href="#head" rel="external nofollow" > 去設(shè)置頁(yè)面內(nèi)錨點(diǎn)定位跳轉(zhuǎn)。具體實(shí)現(xiàn)思路大家跟隨腳本之家小編一起通過本文看下吧2018-07-07
Android使用ListView實(shí)現(xiàn)下拉刷新及上拉顯示更多的方法
這篇文章主要介紹了Android使用ListView實(shí)現(xiàn)下拉刷新及上拉顯示更多的方法,結(jié)合實(shí)例形式分析了ListView滾動(dòng)刷新與加載的相關(guān)操作技巧,需要的朋友可以參考下2017-02-02
淺析Android手機(jī)衛(wèi)士之抖動(dòng)輸入框和手機(jī)震動(dòng)
這篇文章主要介紹了淺析Android手機(jī)衛(wèi)士之輸入框抖動(dòng)和手機(jī)震動(dòng)的相關(guān)資料,需要的朋友可以參考下2016-04-04
Flutter質(zhì)感設(shè)計(jì)之持久底部面板
這篇文章主要為大家詳細(xì)介紹了Flutter質(zhì)感設(shè)計(jì)之持久底部面板,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android開發(fā)實(shí)現(xiàn)Files文件讀取解析功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)Files文件讀取解析功能,結(jié)合實(shí)例形式分析了Android針對(duì)txt文本文件的讀取、保存功能實(shí)現(xiàn)方法與布局操作技巧,需要的朋友可以參考下2017-09-09
Android小程序?qū)崿F(xiàn)選項(xiàng)菜單
這篇文章主要為大家詳細(xì)介紹了Android小程序?qū)崿F(xiàn)選項(xiàng)菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Android流式布局實(shí)現(xiàn)歷史搜索記錄功能
最近在開發(fā)項(xiàng)目的時(shí)候,有一個(gè)需求是展示歷史搜索記錄 ,展示的樣式是流式布局(就是根據(jù)內(nèi)容自動(dòng)換行)。接下來通過本文給大家分享android流式布局實(shí)現(xiàn)歷史搜索記錄功能,感興趣的的小伙伴參考下2017-05-05
Flutter實(shí)現(xiàn)手勢(shì)識(shí)別功能詳解方法
在Flutter中使用GestureDetector可以來完成對(duì)手勢(shì)的識(shí)別,包括長(zhǎng)按、滑動(dòng)、雙擊等手勢(shì),這篇文章主要介紹了Flutter實(shí)現(xiàn)手勢(shì)識(shí)別功能2022-11-11

