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使用友盟集成QQ、微信、微博等第三方分享與登錄方法詳解
之前的項(xiàng)目第三方分享和登錄一直都使用ShareSDK實(shí)現(xiàn)的。為了統(tǒng)一使用友盟的全家桶,所以三方分享和登錄也就選擇了友盟,這里為大家整理出詳細(xì)方法2018-03-03Android之ScrollView嵌套ListView和GridView沖突的解決方法
由于ListView,GridView本身都繼承于ScrollView,一旦在ScrollView中嵌套ScrollView,在ScrollView中嵌套使用ListView或者GridView,ListView只會(huì)顯示一行多一點(diǎn)。兩者進(jìn)行嵌套,即會(huì)發(fā)生沖突2013-09-09大型項(xiàng)目里Flutter測(cè)試應(yīng)用實(shí)例集成測(cè)試深度使用詳解
這篇文章主要為大家介紹了大型項(xiàng)目里Flutter測(cè)試應(yīng)用實(shí)例集成測(cè)試深度使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android Easeui 3.0 即時(shí)通訊的問(wèn)題匯總
這篇文章主要介紹了Android Easeui 3.0 即時(shí)通訊的問(wèn)題匯總的相關(guān)資料,需要的朋友可以參考下2016-09-09Android View移動(dòng)的六種方法小結(jié)
在android開(kāi)發(fā)中,經(jīng)常會(huì)遇到一個(gè)view需要它能夠支持滑動(dòng)的需求。下面通過(guò)本篇文章給大家介紹android view移動(dòng)的六種方法,對(duì)android view移動(dòng)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12RecyclerView嵌套R(shí)ecyclerView滑動(dòng)卡頓的解決方法
這篇文章主要為大家詳細(xì)介紹了RecyclerView嵌套R(shí)ecyclerView滑動(dòng)卡頓的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12Android實(shí)現(xiàn)頂部底部雙導(dǎo)航界面功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)頂部\底部雙導(dǎo)航界面功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Android實(shí)現(xiàn)底部導(dǎo)航欄功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部導(dǎo)航欄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06Android通過(guò)SharedPreferences實(shí)現(xiàn)自動(dòng)登錄記住用戶(hù)名和密碼功能
最近使用SharedPreferences實(shí)現(xiàn)了一個(gè)android自動(dòng)登錄功能,特此分享到腳本之家平臺(tái)供大家參考2017-07-07