自定義一個(gè)voiceview音量調(diào)節(jié)控件

記得以前有一個(gè)需求

QQ截圖20170607115701.png

做一個(gè)播放界面,左邊的是需要這種效果可以隨著拖動(dòng)調(diào)節(jié)音量,然后點(diǎn)擊速圖標(biāo)還可以收縮伸展開(kāi)這個(gè)音量欄,尼瑪當(dāng)初的我做的那個(gè)累啊,整整弄了一個(gè)星期,大概寫了3,4個(gè)組合控件有3000多行代碼以及用了各種切圖,勉強(qiáng)弄好后還有點(diǎn)Bug,還依稀記得我們技術(shù)總監(jiān)最后看我的眼神~~~,當(dāng)然現(xiàn)在翻過(guò)頭來(lái)看這種需求也不是那么特別難了,前段時(shí)間正好沒(méi)事把它擼了出來(lái)。
我們看下怎么實(shí)現(xiàn)的。

public class VoiceView extends View 

首先定義VoiceView

    private void initView() {
        //音量大小默認(rèn)為1
        mSpeedLength = 5;
        //矩形弧度minimum
        mXRound = 30;
        mYRound = 30;

        //每個(gè)item需要的寬度
        mVoiceItemWidth = 10;
        mVoiceItemHeight = 20;
        mMinimumVoiceHeight = mVoiceItemHeight+mVoiceItemHeight*1/3;
        mPointBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.point));

        //初始化音量控件初始狂寬高大小
        mMinWidth=100;
        mMinHeight=30;

        mPointWidth = mVoiceItemWidth*2;
        mCurrVolum = 4;

        //右側(cè)圖片寬高
    }

我在創(chuàng)建控件的時(shí)候定義一個(gè)init方法進(jìn)行一些初始化,這里有初始速度,矩形弧度,每個(gè)音量塊的寬度以及每個(gè)音量塊的高度,音量指示器圖片等,這里我把指示器的寬度設(shè)置為音量塊寬度的二倍。

好我們主要看一下draw方法里面怎么實(shí)現(xiàn)的。主要的邏輯都在這里

 protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int count=0;
        mMeasuredWidth = getMeasuredWidth();
        mMeasuredHeight = getMeasuredHeight();
            Paint backgroundPaint = new Paint();
            backgroundPaint.setColor(Color.parseColor("#a4c2f4"));
            canvas.drawRoundRect(0, 0, mMeasuredWidth, mMeasuredHeight, mXRound, mYRound, backgroundPaint);
            //音量欄所需要的上下左右寬距離
            if(mRightImageBitmap!=null){
                mRightBitmapWidthAndHeight=mMeasuredHeight;
                //mVoiceItemMarginLeft = (mMeasuredWidth - mMeasuredHeight - (mVoiceItemWidth * mSpeedLength))/(mSpeedLength+1);
                RectF rectF = new RectF();
                rectF.set(mMeasuredWidth-mRightBitmapWidthAndHeight,0,mMeasuredWidth,mRightBitmapWidthAndHeight);
                canvas.drawBitmap(mRightImageBitmap,null,rectF,null);
                Log.e("wwww","isnull");
            }else{
                mRightBitmapWidthAndHeight=0;
                //mVoiceItemMarginLeft=(mMeasuredWidth - (mVoiceItemWidth * mSpeedLength))/(mSpeedLength+1);
                Log.e("wwww","isnullNO");
            }
            mVoiceItemMarginLeft = (mMeasuredWidth - mRightBitmapWidthAndHeight - (mVoiceItemWidth * mSpeedLength))/(mSpeedLength+1);
            int voiceLeft;
            int voiceRight;
            backgroundPaint.setColor(Color.WHITE);
            //設(shè)置初始的7個(gè)音量調(diào)節(jié)位置和大小   上下都是不變的變得是左右位置
            for (int i = 0; i < mCurrVolum; i++) {
                voiceLeft = (i + 1) * mVoiceItemMarginLeft + i * mVoiceItemWidth;
                voiceRight = (i + 1) * mVoiceItemMarginLeft + (i +1)* mVoiceItemWidth ;
                canvas.drawRect(voiceLeft, mVoiceItemHeight, voiceRight, mMeasuredHeight - mVoiceItemHeight, backgroundPaint);
                //繪制point
                if(i==(mCurrVolum-1)){
                    int pointLeft = voiceLeft - (mPointWidth-mVoiceItemWidth) / 2;
                    RectF rectF = new RectF();
                    rectF.set(pointLeft,0,pointLeft+mPointWidth,mPointWidth);
                    canvas.drawBitmap(mPointBitmap,null,rectF,null);
                    Log.e("TAG","mCurrVolum:"+mCurrVolum);
                }

            }

             backgroundPaint.setColor(Color.parseColor("#a4c2f4"));
            for (int i = mCurrVolum; i < mSpeedLength; i++) {
                //定義每個(gè)Item音量的寬度
                voiceLeft = (i + 1) * mVoiceItemMarginLeft + i * mVoiceItemWidth;
                voiceRight = (i + 1) * mVoiceItemMarginLeft + i * mVoiceItemWidth + mVoiceItemWidth;
                canvas.drawRect(voiceLeft, mVoiceItemHeight, voiceRight, mMeasuredHeight - mVoiceItemHeight, backgroundPaint);
            }

    }

由于這個(gè)控件實(shí)現(xiàn)的比較單一所以實(shí)現(xiàn)細(xì)節(jié)直接寫里面了沒(méi)有抽出來(lái),
首先繪制矩形,然后我們判斷右邊的bitmap是否為null,因?yàn)檫@是提供的一個(gè)開(kāi)放方法這個(gè)圖片是由我們?cè)O(shè)置進(jìn)去的如果是null,那么mRightBitmapWidthAndHeight設(shè)置為0,否則我們把它的寬和高都設(shè)置為整個(gè)控件的高。

ok右邊的圖片繪制完后,正式開(kāi)始擼我們的音量啦~一開(kāi)始我默認(rèn)設(shè)置音量len=7我們分別繪制7個(gè)音塊

            for (int i = 0; i < mCurrVolum; i++) {
                voiceLeft = (i + 1) * mVoiceItemMarginLeft + i * mVoiceItemWidth;
                voiceRight = (i + 1) * mVoiceItemMarginLeft + (i +1)* mVoiceItemWidth ;
                canvas.drawRect(voiceLeft, mVoiceItemHeight, voiceRight, mMeasuredHeight - mVoiceItemHeight, backgroundPaint);
            }

每個(gè)音塊的左邊距離等我們?cè)O(shè)置的marginleft+音塊的寬度

然后開(kāi)始繪制指示器point

                //繪制point
                if(i==(mCurrVolum-1)){
                    int pointLeft = voiceLeft - (mPointWidth-mVoiceItemWidth) / 2;
                    RectF rectF = new RectF();
                    rectF.set(pointLeft,0,pointLeft+mPointWidth,mPointWidth);
                    canvas.drawBitmap(mPointBitmap,null,rectF,null);
                    Log.e("TAG","mCurrVolum:"+mCurrVolum);
                }

這里我們把指示器默認(rèn)繪制在第四檔的位置,這里需要注意下,由于指示器的寬度是音塊寬度的二倍所以指示器的
左側(cè)距離=第四個(gè)音塊的左側(cè)距離-(指示器寬度-音塊寬度)/2
好了這里我們指示器和音塊全部繪制完畢了

 if(i==(mCurrVolum-1))

這里為啥要去-1呢你想啊我們繪制音塊的時(shí)候是從0開(kāi)始的,假如
mCurrVolum值是4當(dāng)然要在index=3處繪制這個(gè)時(shí)候音塊長(zhǎng)度為4

但是這個(gè)控件不能是靜態(tài)的啊,我們要滑動(dòng)控制它啊,我們重寫一下
onTouchEvent方法

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                return true;

            case ACTION_MOVE:
                getScrollLength(event);
                invalidate();
                return true;
            case MotionEvent.ACTION_UP:
                getScrollLength(event);
                invalidate();
                return true;

        }
        return super.onTouchEvent(event);
    }

可以看到代碼并不復(fù)雜,在滑動(dòng)和停止滑動(dòng)時(shí)候都調(diào)用了getscrolllenth()這個(gè)方法是個(gè)什么鬼我們貼上代碼看看


    private void getScrollLength(MotionEvent event) {
        int eventX= (int) (event.getX()+0.5f);
/*
        if(eventX>0&&eventY>0&&eventX<mMeasuredWidth-mMeasuredHeight&&eventY<mMeasuredHeight){*/

             //方案1:
            int  marginLeftAndVoiceWidth= (mMeasuredWidth - mRightBitmapWidthAndHeight - mVoiceItemMarginLeft) / mSpeedLength;

             //方案2:
            //int  marginLeftAndVoiceWidth= mVoiceItemMarginLeft;
            mCurrVolum=eventX/marginLeftAndVoiceWidth;
            if(mCurrVolum>mSpeedLength){
                mCurrVolum=mSpeedLength;
            }
            Log.e("TAG","volum:"+mCurrVolum);
            if(mOnSpeedClickListener!=null){
                mOnSpeedClickListener.onSpeedChange(mCurrVolum);
            }
    }

這里采用的方案1是當(dāng)我們觸摸到每個(gè)音塊最右邊的時(shí)候,這個(gè)音塊顯示或者消失,而方案2是觸摸到音塊左邊的時(shí)候顯示消失,這個(gè)根據(jù)個(gè)人習(xí)慣選擇了。
我們用控件寬度-最右側(cè)圖標(biāo)的寬度-音塊的左邊距/音量長(zhǎng)度就可以得到每個(gè)音塊+左邊距長(zhǎng)度

我們根據(jù)這個(gè)值和我們手指滑動(dòng)的距離跟新我們的音量大小,拿我們滑動(dòng)的當(dāng)前位置eventX/剛才計(jì)算的邊距 =當(dāng)前音量位置然后把結(jié)果賦值給我們mCurrVolum重新繪制一下,音量就更新好啦。

最終我們實(shí)現(xiàn)的效果如下

vBwQjCjwME.gif

3000多行代碼擼出來(lái)的效果現(xiàn)在200行左右就全部搞定省時(shí)省力,哈
這個(gè)控件雖然不是很復(fù)雜但是還是有應(yīng)用場(chǎng)景的的,貼上git地址:
老鐵們隨手給個(gè)Star支持下我這小小的進(jìn)步哈 ~
https://github.com/boboyuwu/voice-view

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,094評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,405評(píng)論 4 61
  • 杲杲日出,彼草離離。 行邁靡靡,中心搖搖。 知我者知我所思,不知我者多說(shuō)無(wú)益。 杲杲日出,彼稻青青。 行邁靡靡,中...
    倚詩(shī)愛(ài)世閱讀 329評(píng)論 0 1
  • 文.孫亮來(lái)到一間咖啡巴 他和她對(duì)面坐下 他面對(duì)著她開(kāi)始慌了神的表達(dá) 她看著他在述說(shuō)生活里的枝芽 一杯咖啡放糖 一杯...
    朦朧詩(shī)人孫亮閱讀 357評(píng)論 1 4
  • 為了把孩子培養(yǎng)成大腦的主人,要相信孩子的大腦是一個(gè)完整的客觀存在。也就是說(shuō)承認(rèn)孩子是一個(gè)獨(dú)立的人性個(gè)體,其具有無(wú)限...
    金勇Maya閱讀 228評(píng)論 0 1

友情鏈接更多精彩內(nèi)容