Android語音聲波控件 Android條形波控件
許久不來 , 冒個(gè)泡 , 發(fā)一個(gè)剛做的聲音波動(dòng)的View吧 :
代碼不多 , 沒什么技術(shù)含量 , 權(quán)當(dāng)給您省時(shí)間了 , 直接復(fù)制粘貼就能用 , 直接上代碼:
SoundWavesView
/** * 語音通話的聲波控件 * Created by Mr.LongFace on 2017/9/16. */ public class SoundWavesView extends View { private int mMini; // 最短值 private int mMax; // 最大值 private int mLineWidth; // 每條聲波的寬度 private int mSoundNum = 5; // 聲波的數(shù)量 private int mSpac; // 每條聲波的中點(diǎn) private int mWidth , mHeight; // 控件寬高 private boolean isRun = false; private Paint mPaint; private RectF mRectF; private List<SoundLine> mSoundList = new ArrayList<>(); private Handler mHandler = new Handler(); private Runnable mInvalidateRun = new Runnable() { @Override public void run() { postInvalidate(); } }; public SoundWavesView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(getResources().getColor(R.color.color_red)); mPaint.setStyle(Paint.Style.FILL); mRectF = new RectF(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (widthMeasureSpec > 0 && heightMeasureSpec > 0) { initParam(); } } private void initParam() { mWidth = getWidth(); mHeight = getHeight(); mMini = (int) (mHeight * 0.3f); mMax = mHeight; initLines(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < mSoundNum; i++) { SoundLine sound = mSoundList.get(i); mRectF.left = sound.left; mRectF.right = sound.right; mRectF.top = sound.top; mRectF.bottom = sound.bottom; canvas.drawRoundRect(mRectF , mLineWidth / 2 , mLineWidth / 2 , mPaint); } if (isRun) { mHandler.postDelayed(mInvalidateRun, 10); } } @Override protected void onVisibilityChanged(@NonNull View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if (isRun) { if (visibility == VISIBLE) { if (mWidth == 0) { initParam(); } if (mSoundList != null && mSoundList.size() > 0) { for (SoundLine soundLine : mSoundList) { soundLine.start(); } } }else{ if (mSoundList != null && mSoundList.size() > 0) { for (SoundLine soundLine : mSoundList) { soundLine.stop(); } } } } } public void start() { if (!isRun) { isRun = true; for (SoundLine sound : mSoundList) { sound.start(); } postInvalidate(); } } public void stop(){ if (isRun) { isRun = false; for (SoundLine sound : mSoundList) { sound.stop(); } } } private void initLines() { mLineWidth = (int) (mWidth / mSoundNum * 0.7f); mSpac = mWidth / (mSoundNum - 1); mSoundList.clear(); chaos(); } /** * 生成凌亂的 */ private void chaos() { for (int i = 0; i < mSoundNum; i++) { int left = i * mSpac - mLineWidth / 2; int right = i * mSpac + mLineWidth / 2; SoundLine s = new SoundLine(left , right , 0 , mHeight); s.setMode(SoundLine.SPEED_RAN); s.setBorder(mMini , mMax); mSoundList.add(s); } } /** * 生成波浪的 */ private void wave(){ // TODO 防止UI抽風(fēng) } /** * 生成有序的 */ private void order(){ // TODO 防止UI抽風(fēng) } }
SoundLine
/** * 語音音頻波紋的單個(gè)音波屬性 * Created by Mr.LongFace on 2017/9/16. */ public class SoundLine implements ValueAnimator.AnimatorUpdateListener{ // 低 中 高 隨機(jī) 4擋 public static final int SPEED_LOW = 500; public static final int SPEED_MID = 200; public static final int SPEED_HEI = 0; public static final int SPEED_RAN = 0; private Random mRandom; private ValueAnimator mAnim; public int left , right , top , bottom; private int min , max; public SoundLine(int left , int right , int top , int bottom){ this.left = left; this.right = right; this.top = top; this.bottom = bottom; mRandom = new Random(); initAnim(); } private void initAnim() { mAnim = ValueAnimator.ofFloat(0.0f , 1.0f); setMode(SPEED_MID); mAnim.setRepeatCount(-1); mAnim.setRepeatMode(ValueAnimator.REVERSE); mAnim.addUpdateListener(this); } public void setMode(int mode){ if (mode == SPEED_RAN) { mode = mRandom.nextInt(400); } mAnim.setDuration(300 + mode); } public void start(){ if (mAnim.isRunning()){ mAnim.end(); } mAnim.start(); } @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float f = (float) valueAnimator.getAnimatedValue(); top = (int) (f * (max - min) / 2); bottom = max - top; } public void setBorder(int min, int max) { this.min = min; this.max = max; } public void stop() { mAnim.end(); mAnim.cancel(); } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 自定義ListView實(shí)現(xiàn)QQ空間界面(說說內(nèi)包含圖片、視頻、點(diǎn)贊、評論、轉(zhuǎn)發(fā)功能)
這篇文章主要介紹了Android 自定義ListView實(shí)現(xiàn)QQ空間界面,qq空間說說內(nèi)包含圖片、視頻、點(diǎn)贊、評論、轉(zhuǎn)發(fā)功能,需要的朋友可以參考下2019-12-12Android XRecyclerView最簡單的item點(diǎn)擊事件處理
這篇文章主要為大家詳細(xì)介紹了Android XRecyclerView最簡單的item點(diǎn)擊事件處理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12在Android中使用SQLite數(shù)據(jù)庫及其操作詳解
在?Android?開發(fā)中,使用?SQLite?數(shù)據(jù)庫是一種常見的持久化數(shù)據(jù)存儲方式,本文將通過代碼示例詳細(xì)講解如何在?Android?中創(chuàng)建數(shù)據(jù)庫表、插入數(shù)據(jù)、執(zhí)行查詢操作以及驗(yàn)證查詢結(jié)果,需要的朋友可以參考下2024-08-08android中在Activity中響應(yīng)ListView內(nèi)部按鈕的點(diǎn)擊事件的兩種方法
本篇文章主要介紹了android中在Activity中響應(yīng)ListView內(nèi)部按鈕的點(diǎn)擊事件的兩種方法,有需要的可以了解一下。2016-11-11android新建草稿刪除后下次開機(jī)還會顯示保存的草稿
android 新建一個(gè)草稿,保存,然后全部刪除會話,關(guān)機(jī)再開機(jī)后還會顯示保存的草稿,下面與大家分享下具體的解決方法2013-06-06Android動(dòng)態(tài)模糊效果的快速實(shí)現(xiàn)方法
這篇文章主要介紹了Android動(dòng)態(tài)模糊效果的快速實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01