Android自定義View實(shí)現(xiàn)音頻播放圓形進(jìn)度條
本篇文章介紹自定義View配合屬性動(dòng)畫(huà)來(lái)實(shí)現(xiàn)如下的效果

實(shí)現(xiàn)思路如下:
- 根據(jù)播放按鈕的圖片大小計(jì)算出圓形進(jìn)度條的大小
- 根據(jù)音頻的時(shí)間長(zhǎng)度計(jì)算出圓形進(jìn)度條繪制的弧度
- 通過(guò)Handler刷新界面來(lái)更新圓形進(jìn)度條的進(jìn)度
具體實(shí)現(xiàn)過(guò)程分析:
首先來(lái)看看自定義View中定義的一些成員變量
//表示坐標(biāo)系中的一塊矩形區(qū)域 private RectF mRectF; //畫(huà)筆 private Paint mPaint; //畫(huà)筆寬度 private int mCircleStoreWidth = 3; //最大進(jìn)度值 private int mMaxProcessValue = 100; //進(jìn)度值 private int mProcessValue; private int width; private int height; //播放器按鈕id值 private int bitmapPlay; private int bitmapStop; //播放器按鈕Bitmap對(duì)象 private Bitmap drawBitmapPlay; private Bitmap drawBitmapStop; private Context context; //標(biāo)記是否正在播放中 private boolean isPlay;
初始化自定義View,在這里獲取播放器按鈕圖片以及初始化畫(huà)布畫(huà)筆對(duì)象以及設(shè)置將畫(huà)筆設(shè)置抗鋸齒
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
this.context = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.circle_progress_image_attrs);
bitmapPlay = a.getResourceId(R.styleable.circle_progress_image_attrs_play_image, R.mipmap.play_button);
bitmapStop = a.getResourceId(R.styleable.circle_progress_image_attrs_stop_image, R.mipmap.stop_button);
a.recycle();
drawBitmapPlay = BitmapFactory.decodeResource(context.getResources(), bitmapPlay);
drawBitmapStop = BitmapFactory.decodeResource(context.getResources(), bitmapStop);
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
這里使用了自定義attrs來(lái)獲取播放器按鈕圖片
在attrs.xml中新建如下:
<declare-styleable name="circle_progress_image_attrs">
<attr name="play_image" format="reference"/>
<attr name="stop_image" format="reference"/>
</declare-styleable>
然后在xml布局的自定義View中加入就能獲取圖片的id值了
circle:play_image="@mipmap/play_button" circle:stop_image="@mipmap/stop_button"
然后我們重寫(xiě)onMeasure()來(lái)測(cè)量圓形進(jìn)度條繪制的位置
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = measureWidth(widthMeasureSpec);
height = measureWidth(heightMeasureSpec);
mRectF.left = width / 2 - drawBitmapPlay.getWidth() / 2;
mRectF.top = height / 2 - drawBitmapPlay.getHeight() / 2;
mRectF.right = width / 2 + drawBitmapPlay.getWidth() / 2;
mRectF.bottom = height / 2 + drawBitmapPlay.getHeight() / 2;
}
public int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = 200;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(specSize, result);
}
}
return result;
}
獲取播放器按鈕圖片的大小后,計(jì)算出進(jìn)度條的相應(yīng)的坐標(biāo)放入RectF對(duì)象中,RectF對(duì)象是用來(lái)表示坐標(biāo)系中的一塊矩形區(qū)域,用于在特定的位置畫(huà)圖
然后我們就可以通過(guò)重寫(xiě)onDraw()方法來(lái)繪制View了
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.TRANSPARENT);
//畫(huà)圓
mPaint.setColor(ContextCompat.getColor(context, R.color.orange));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mCircleStoreWidth);
// canvas.drawArc(mRectF, -90, 360, false, mPaint);
mPaint.setColor(ContextCompat.getColor(context, R.color.gray));
canvas.drawArc(mRectF, -90, ((float) mProcessValue / mMaxProcessValue) * 360, false, mPaint);
Log.d(TAG, ((float) mProcessValue / mMaxProcessValue) * 360 + "");
float imageLeft = width / 2 - drawBitmapPlay.getWidth() / 2;
float imageTop = height / 2 - drawBitmapPlay.getHeight() / 2;
if (isPlay) {
canvas.drawBitmap(drawBitmapStop, imageLeft, imageTop, mPaint);
} else {
canvas.drawBitmap(drawBitmapPlay, imageLeft, imageTop, mPaint);
}
}
要點(diǎn)其實(shí)就是canvas.drawArc()方法在RecfF的位置里畫(huà)弧形,通過(guò)音頻播放的開(kāi)始時(shí)間/總時(shí)間*360來(lái)計(jì)算出弧度
要注意的是每次調(diào)用onDraw()方法的時(shí)候都需要先將canvas畫(huà)透明色來(lái)起到清屏的作用
通過(guò)handler來(lái)每150毫秒刷新一次界面
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//定時(shí)更新界面
if (isPlay) {
mProcessValue += 150;
if (mProcessValue == mMaxProcessValue) {
isPlay = false;
}
invalidate();
Message message = handler.obtainMessage(1);
handler.sendMessageDelayed(message, 150);
}
}
super.handleMessage(msg);
}
};
最后是一些包裝方法,很簡(jiǎn)單不仔細(xì)介紹了
public void play() {
isPlay = true;
Message message = handler.obtainMessage(1);
handler.sendMessageDelayed(message, 150);
}
public void setDuration(int duration) {
this.mMaxProcessValue = duration;
}
public void clearDuration() {
this.mMaxProcessValue = 0;
this.mProcessValue = 0;
}
public void pause() {
isPlay = false;
invalidate();
}
public void stop() {
isPlay = false;
this.mMaxProcessValue = 0;
this.mProcessValue = 0;
invalidate();
}
音頻播放的邏輯實(shí)現(xiàn)部分因?yàn)椴粚儆谧远xview因此可以自行參考demo
代碼示例: CustomViewSamples
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 自定義View實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條功能
- Android自定義View實(shí)現(xiàn)水平帶數(shù)字百分比進(jìn)度條
- Android自定義View實(shí)現(xiàn)漸變色進(jìn)度條
- Android自定義View實(shí)現(xiàn)加載進(jìn)度條效果
- Android自定義帶進(jìn)度條WebView仿微信加載過(guò)程
- Android view自定義實(shí)現(xiàn)動(dòng)態(tài)進(jìn)度條
- Android 自定義view和屬性動(dòng)畫(huà)實(shí)現(xiàn)充電進(jìn)度條效果
- android 自定義view實(shí)現(xiàn)彩虹進(jìn)度條功能
相關(guān)文章
Android平臺(tái)中實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)的5種方式
這篇文章主要為大家分享了介紹了Android平臺(tái)中實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)技術(shù)的5種方式,供大家學(xué)習(xí),感興趣的小伙伴們可以參考一下2016-06-06
Android 自定義ContentProvider簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android 自定義ContentProvider簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android 詳解自定義圓角輸入框和按鈕的實(shí)現(xiàn)流程
對(duì)于安卓程序員來(lái)說(shuō),自定義view簡(jiǎn)直不要太重要,畢竟有很多功能,譬如圓形頭像這些,用單純的原生非常難以實(shí)現(xiàn),而用自定義view,簡(jiǎn)直分分鐘,今天我們來(lái)實(shí)現(xiàn)自定義圓角輸入框和按鈕,大家可以跟著練習(xí),掌握技巧2021-11-11
Android連接MySQL數(shù)據(jù)庫(kù)詳細(xì)教程
在Android應(yīng)用程序中連接 MySQL 數(shù)據(jù)庫(kù)可以幫助開(kāi)發(fā)人員實(shí)現(xiàn)更豐富的數(shù)據(jù)管理功能,本教程將介紹如何在Android應(yīng)用程序中使用低版本的MySQL Connector/J驅(qū)動(dòng)程序來(lái)連接MySQL數(shù)據(jù)庫(kù),需要的朋友可以參考下2023-05-05
Android實(shí)現(xiàn)系統(tǒng)重新啟動(dòng)的功能
有些Android版本沒(méi)有系統(tǒng)重啟的功能,非常不方便。需要我們自己開(kāi)發(fā)一個(gè)能夠重新啟動(dòng)的應(yīng)用2013-11-11
Android Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器APP
這篇文章主要為大家詳細(xì)介紹了Android Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器APP,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03
Android實(shí)現(xiàn)單頁(yè)面浮層可拖動(dòng)view的一種方法
本篇文章主要介紹了Android實(shí)現(xiàn)單頁(yè)面浮層可拖動(dòng)view的一種方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10

