Android microphone custom View with dynamic display of Audio Tape Volume
1. The so-called no picture, no truth, first. What we need to achieve is the button of the middle recording, and the surrounding area will display a waveform of the volume size.
2. VolumCircleBar inherits from View and we have customized it. The Code is as follows:
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHByZSBjbGFzcz0 = "brush: java;"> 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. attribute Set; import android. view. view; import com. panshi. xuexiao. r;/*** microphone volume round button * @ author hiphonezhu@gmail.com * @ version [CCEnglish, 2014-7-25] */public class VolumCircleBar extends View {private double volumRate; // volume percentage private boolean isRecording; // recording mark private Object lock = new Object (); private Thread uiThread; private Paint mPaint; private RectF arcRect; private Matrix matrix = new Matrix (); pr Ivate final int VOLUM_INDICATE_LENGTH = 5; // volume size line length private final int CIRCLE_INNER_DISTANCE_TO_OUTSIDE = 5; // The distance from the incircle to the outer circle 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 typed Array = context. getTheme (). obtainStyledAttributes (attrs, R. styleable. volumCircleBar, defStyle, 0); init (typedArray);} private int recordingColor; // recording background color private int stoppedColor; // stop background color private Bitmap centerRes; // private int totalBlockCount in the middle microphone image; // number of blocks private int spliteAngle; // The angle between blocks private int circleWidth; // diameter/*** initialization */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 (). g EtResources (), 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 Ill EgalArgumentException ("spliteAngle * blockCount> 360, while the result shocould be less than 360. ") ;}// debug for test isRecording = true; volumRate = 0.5 ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {// diameter int width = MeasureSpec. getSize (widthMeasureSpec); int height = MeasureSpec. getSize (heightMeasureSpec); circleWidth = width> height? Width: height; if (arcRect = null) {arcRect = new RectF (rows, rows, circleWidth-CIRCLE_INNER_DISTANCE_TO_OUTSIDE, circleWidth-rows); // The volume display area, several pixels inside the offset // image processing matrix initBitmapMatrix ();} // forcibly set the view Size setMeasuredDimension (circleWidth, circleWidth );} /*** intermediate image compression processing */private void initBitmapMatrix () {float inn ErCircleRadius = (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 + Length + innerCircleRadius-innerRectangleWidth/2; // offset if (centerRes. getWidth ()> (innerRectangle Width) | centerRes. getHeight ()> (innerRectangleWidth) {// The image width or height is greater than (diameter-inner offset), and the ratio of compression if (centerRes. getWidth ()> centerRes. getHeight () {// float ratio = innerRectangleWidth/centerRes. getWidth (); matrix. postScale (ratio, ratio); float translateY = (innerRectangleWidth-(centerRes. getHeight () * ratio)/2f; // offset to ensure that the matrix is displayed in the center of the image. postTranslate (translateOffset, translateY + trans LateOffset);} else {// float ratio = innerRectangleWidth/(centerRes. getHeight () * 1.0f); matrix. postScale (ratio, ratio); float translateX = (innerRectangleWidth-(centerRes. getWidth () * ratio)/2f; // offset in the horizontal direction to ensure that the matrix is displayed in the center of the image. postTranslate (translateX + translateOffset, translateOffset);} else {// when the width and height of the image are smaller than the screen width, the float translateX = (innerRectangleWidth-centerRes is displayed in the center of the image. get Width ()/2f; float translateY = (innerRectangleWidth-centerRes. getHeight ()/2f; matrix. postTranslate (translateX + translateOffset, translateY + translateOffset);}/*** set the volume percentage * @ param rate */public void updateVolumRate (double rate) {synchronized (lock) {this. volumRate = rate; if (Thread. currentThread ()! = UiThread) {postInvalidate () ;}else {invalidate () ;}}/ *** start/stop recording */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) // recording in progress {// 1. draw a Green Circle mPaint. setAntiAlias (true); // eliminate the Sawtooth mPaint. setColor (recordingColor); mPaint. setStrokeWidth (1); mPaint. setStyle (Paint. style. FILL); // FILL the canvas. drawCircle (circleWidth/2f, circleWidth/2f, circleWidth/2f, mPaint); // 2. calculate the volume based on the volume percentage, number of blocks, and block interval. dynamically draw the volume size. // calculate the block angle. float blockAngle = (360 * 1.0f-spliteAngle * totalBlockCount)/totalBlockCount; int drawBlockCount = (int) (totalBlockCount * volumRate); // number of blocks drawn mPaint. setStrokeWidth (VOLUM_INDICATE_LENGTH); mPaint. setColor (stoppedColor); mPaint. setStyle (Paint. style. STROKE); // Hollow for (int I = 0; I <drawBlockCount; I ++) {canvas. drawArc (arcRect, I * (blockAngle + spliteAngle)-90, blockAngle, false, mPaint) ;}} else // stop recording {// 1. draw a gray circle mPaint. setColor (stoppedColor); mPaint. setStrokeWidth (1); mPaint. setStyle (Paint. style. FILL); // FILL the canvas. drawCircle (circleWidth/2f, circleWidth/2f, circleWidth/2f, mPaint) ;}// draw the middle microphone canvas. drawBitmap (centerRes, matrix, null );}}
There is not much time today. I can leave a message without understanding it.