Android麥克風錄音帶音量大小動態顯示的圓形自訂View

來源:互聯網
上載者:User

標籤:android   style   blog   http   java   color   os   strong   

1、所謂無圖無真相,先上。我們要實現的就是中間那個錄音的按鈕,周邊會顯示一圈音量大小的波形

2、VolumCircleBar繼承自View,我們進行了自訂,代碼如下

package com.rdinfo.ccenglish.ui.ccprofile.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;import com.panshi.xuexiao.R;/** * 麥克風音量圓形按鈕 * @author [email protected] * @version [CCEnglish, 2014-7-25] */public class VolumCircleBar extends View{    private double volumRate; // 音量百分比    private boolean isRecording; // 錄音標誌    private Object lock = new Object();    private Thread uiThread;    private Paint mPaint;    private RectF arcRect;    private Matrix matrix = new Matrix();    private final int VOLUM_INDICATE_LENGTH = 5; // 音量大小線長度    private final int CIRCLE_INNER_DISTANCE_TO_OUTSIDE = 5; // 內切圓距離外圓的距離    public VolumCircleBar(Context context)    {        this(context, null);    }        public VolumCircleBar(Context context, AttributeSet attrs)    {        this(context, attrs, 0);    }        public VolumCircleBar(Context context, AttributeSet attrs, int defStyle)    {        super(context, attrs, defStyle);        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VolumCircleBar, defStyle, 0);         init(typedArray);    }        private int recordingColor; // 錄音背景色    private int stoppedColor; // 停止背景色    private Bitmap centerRes; // 中間麥克風圖片    private int totalBlockCount; // 塊數量    private int spliteAngle; // 塊之間的間隔角度大小    private int circleWidth; // 直徑    /**     * 初始化     */    private void init(TypedArray typedArray)    {        for (int i = 0; i < typedArray.length(); i++)          {              int attr = typedArray.getIndex(i);              switch (attr)            {                case R.styleable.VolumCircleBar_recordingColor:                    recordingColor = typedArray.getColor(i, Color.GREEN);                    break;                case R.styleable.VolumCircleBar_stoppedColor:                    stoppedColor = typedArray.getColor(i, Color.GRAY);                    break;                case R.styleable.VolumCircleBar_centerRes:                    centerRes = BitmapFactory.decodeResource(getContext().getResources(), typedArray.getResourceId(i, R.drawable.ic_launcher));                    break;                case R.styleable.VolumCircleBar_blockCount:                    totalBlockCount = typedArray.getInt(i, 50);                    break;                case R.styleable.VolumCircleBar_splitAngle:                    spliteAngle = typedArray.getInt(i, 2);                    break;            }        }          typedArray.recycle();          uiThread = Thread.currentThread();        mPaint = new Paint();        if (spliteAngle * totalBlockCount > 360)        {            throw new IllegalArgumentException("spliteAngle * blockCount > 360, while the result should be less than 360.");        }                // debug for test        isRecording = true;        volumRate = 0.5;    }        @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        // 直徑        int width = MeasureSpec.getSize(widthMeasureSpec);        int height = MeasureSpec.getSize(heightMeasureSpec);        circleWidth = width > height? width : height;        if (arcRect == null)        {            arcRect = new RectF(CIRCLE_INNER_DISTANCE_TO_OUTSIDE, CIRCLE_INNER_DISTANCE_TO_OUTSIDE,                     circleWidth - CIRCLE_INNER_DISTANCE_TO_OUTSIDE, circleWidth - CIRCLE_INNER_DISTANCE_TO_OUTSIDE); // 音量顯示地區, 內位移幾個像素            // 圖片處理矩陣            initBitmapMatrix();        }        // 強制設定view大小        setMeasuredDimension(circleWidth, circleWidth);    }        /**     * 中間圖片壓縮處理     */    private void initBitmapMatrix()    {        float innerCircleRadius = (circleWidth - 2 * (VOLUM_INDICATE_LENGTH + CIRCLE_INNER_DISTANCE_TO_OUTSIDE)) / 2f; // 內圓的半徑        float innerRectangleWidth = (float)Math.cos((Math.PI / 180) * 45) * innerCircleRadius * 2; // 內圓的內切正方形的邊長        float translateOffset = VOLUM_INDICATE_LENGTH + CIRCLE_INNER_DISTANCE_TO_OUTSIDE + innerCircleRadius - innerRectangleWidth / 2; // 位移的offset        if (centerRes.getWidth() > (innerRectangleWidth) || centerRes.getHeight() > (innerRectangleWidth))        {            // 圖片寬度或高度大於(直徑-內位移), 等比壓縮            if (centerRes.getWidth() > centerRes.getHeight())            {                // 按照寬度壓縮                float ratio = innerRectangleWidth / centerRes.getWidth();                matrix.postScale(ratio, ratio);                float translateY = (innerRectangleWidth - (centerRes.getHeight() * ratio)) / 2f;                // 在縱座標方向上進行位移,以保證圖片置中顯示                matrix.postTranslate(translateOffset, translateY + translateOffset);            }            else            {                // 按照高度壓縮                float ratio = innerRectangleWidth / (centerRes.getHeight() * 1.0f);                matrix.postScale(ratio, ratio);                float translateX = (innerRectangleWidth - (centerRes.getWidth() * ratio)) / 2f;                // 在橫座標方向上進行位移,以保證圖片置中顯示                matrix.postTranslate(translateX + translateOffset, translateOffset);            }        }        else        {            // 當圖片的寬高都小於螢幕寬高時,直接讓圖片置中顯示            float translateX = (innerRectangleWidth - centerRes.getWidth()) / 2f;            float translateY = (innerRectangleWidth - centerRes.getHeight()) / 2f;            matrix.postTranslate(translateX + translateOffset, translateY + translateOffset);        }    }        /**     * 設定音量百分比     * @param rate     */    public void updateVolumRate(double rate)    {        synchronized (lock)        {            this.volumRate = rate;            if (Thread.currentThread() != uiThread)            {                postInvalidate();            }            else            {                invalidate();            }        }    }        /**     * 開始、停止錄音     */    public void toggleRecord()    {        synchronized (lock)        {            isRecording = !isRecording;            if (Thread.currentThread() != uiThread)            {                postInvalidate();            }            else            {                invalidate();            }        }    }        @Override    protected void onDraw(Canvas canvas)    {        super.onDraw(canvas);        canvas.drawColor(Color.TRANSPARENT);         synchronized (lock)        {            if (isRecording) // 正在錄音            {                //1.繪製綠色圓圈                mPaint.setAntiAlias(true); //消除鋸齒                   mPaint.setColor(recordingColor);                mPaint.setStrokeWidth(1);                mPaint.setStyle(Paint.Style.FILL); // 填充                canvas.drawCircle(circleWidth / 2f, circleWidth / 2f, circleWidth / 2f, mPaint);                //2.根據音量百分比、塊數量、塊間隔大小計算角度動態繪製音量大小                // 計算塊的角度                float blockAngle = (360 * 1.0f - spliteAngle * totalBlockCount) / totalBlockCount;                int drawBlockCount = (int)(totalBlockCount * volumRate); // 繪製的block數量                mPaint.setStrokeWidth(VOLUM_INDICATE_LENGTH);                mPaint.setColor(stoppedColor);                mPaint.setStyle(Paint.Style.STROKE); // 空心                for (int i = 0; i < drawBlockCount; i++)                {                    canvas.drawArc(arcRect, i * (blockAngle + spliteAngle) - 90, blockAngle, false, mPaint);                }            }             else // 錄音停止            {                //1.繪製灰色圓圈                mPaint.setColor(stoppedColor);                mPaint.setStrokeWidth(1);                mPaint.setStyle(Paint.Style.FILL); // 填充                canvas.drawCircle(circleWidth / 2f, circleWidth / 2f, circleWidth / 2f, mPaint);            }        }        // 繪製中間話筒        canvas.drawBitmap(centerRes, matrix, null);    }}

今天時間不多,沒看明白的留言吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.