rendering
implementation
The overall flow chart is as followsThe main steps are divided into three parts1. Calculate how many columns of audio blocks the width can hold. 2. Count the number of audio blocks in each column 3. Draw audio blocks
1. Calculate how many columns of audio blocks the width can hold. DanceGap = danceGap = danceGap = danceGap = danceGap
/** * Calculate how many audio blocks can fit in the current width */
val widthNum = (getAvailableWith() / (danceGap + danceWidth)).toInt()
/** * gets the available width */
private fun getAvailableWith(a) = mCanvasWidth - paddingLeft - paddingRight
Copy the code
2. Calculate the number of audio blocks in each column. After calculating how many audio blocks can be placed horizontally, traverse across the column and then draw the audio blocks in the column.
mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
@Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
int samplingRate) {
BaseVisualizer.this.mRawAudioBytes = bytes;
invalidate();
}
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] bytes,
int samplingRate) {
}
}, Visualizer.getMaxCaptureRate() / 2.true.false);
Copy the code
The size of the array of mRawAudioBytes is 128 and the range of the array is -128,127. The first operation is to map the values of mRawAudioBytes to the number of audio files. The second one is how to take the value of the mRawAudioBytes array.
/** * Calculate how many audio blocks can fit in the current width */
val widthNum = (getAvailableWith() / (danceGap + danceWidth)).toInt()
Log.d(
TAG,
"widthNum $widthNum"
)
/** * figure out how much space can be placed horizontally, then draw */
/** * is used to mark the starting position */ when drawing
var lastDanceRight = paddingLeft.toFloat()
if (widthNum > 0&& mRawAudioBytes ! =null && mRawAudioBytes.isNotEmpty())
for (i in 0 until widthNum) {
// Calculate the current height first, and then calculate how many audio blocks can fit at this height
val num = (getAvailableHeight() / (danceHeight + danceGap)).toInt()
val index = (mRawAudioBytes.size) * (i.toFloat() / widthNum)
val b = (mRawAudioBytes[index.toInt()] + 128).toFloat() / 255f
var heightNum =
(b * num).toInt()
if (heightNum < miniNum) {
heightNum = miniNum
}
if (heightNum > maxNum) {
heightNum = maxNum
}
// Get the top height
var lastHeight = mCanvasHeight - paddingStart.toFloat()
Log.d(
TAG,
"heightNum $heightNum lastHeight $lastHeight lastDanceRight $lastDanceRight ${mRawAudioBytes[i]} $num $b $index"
)
lastHeight = drawItem(heightNum, lastDanceRight, lastHeight, canvas)
lastDanceRight += danceWidth + danceGap
}
Copy the code
First of all, there may be 0 to n bars in the file, but the size of mRawAudioBytes is 128. Make a map of the subscripts as you traverse the bars to make sure the values are uniform.
/** get index */ from this mapping
val index = (mRawAudioBytes.size) * (i.toFloat() / widthNum)
Copy the code
The second mapping is an array of mRawAudioBytes representing the size of the audio file. Now map the values of this array to the height of the column. The higher the value, the higher the height, the more audio blocks.
val num = (getAvailableHeight() / (danceHeight + danceGap)).toInt()
val b = (mRawAudioBytes[index.toInt()] + 128).toFloat() / 255f
var heightNum =(b * num).toInt()
Copy the code
The value of mRawAudioBytes is used to calculate the maximum number of audio blocks displayed in the current column. This step is also called normalization, interval mapping.
3. Draw each audio block
private fun drawItem(
heightNum: Int,
lastDanceRight: Float,
lastHeight: Float,
canvas: Canvas?).: Float {
var lastHeight1 = lastHeight
for (j in 0 until heightNum) {
mDanceRect.set(
lastDanceRight,
lastHeight1 - danceHeight,
lastDanceRight + danceWidth,
lastHeight1
)
mPaint.shader = null
if (j >= heightNum - shaderNum) {
val backGradient = LinearGradient(
lastDanceRight,
lastHeight1 - danceHeight,
lastDanceRight + danceWidth,
lastHeight1,
intArrayOf(colorStart, colorCenter, colorEnd),
null, Shader.TileMode.CLAMP ) mPaint.shader = backGradient } canvas? .drawRoundRect(mDanceRect,8f.8f, mPaint)
lastHeight1 -= (danceHeight + danceGap)
}
return lastHeight1
}
Copy the code
Figure out how many rectangle blocks can be drawn in a column. Each rectangle block is a Rectangle. Then draw a Rectangle.
Making the address
Welcome to like collection, later will optimize github.com/hankinghu/A…
Method of use
<com.masoudss.lib.DanceView
android:id="@+id/danceView"
android:layout_width="320dp"
android:layout_height="300dp"
android:layout_gravity="center"
app:color_center="@color/red"
app:color_end="@color/white"
app:color_start="@color/yellow"
app:dance_color="@color/yellow"
app:dance_corner_radius="2dp"
app:dance_gap="2dp"
app:max_dance_num="30"
app:min_dance_num="2"
app:shader_num="3" />
Copy the code
- Shader_num Number of gradients to add to the top
- Color_end Gradient tail color
- Color_start Gradient start color
- Color_center Gradient middle color
- Min_dance_num Minimum number of entries in each column
- Max_dance_num Maximum number of columns to display
- Dance_gap The distance between each audio bar