音乐播放时跳动的音符

最近做音乐研究了下音乐跳动时的view。这里记录下,以后查找方便:


import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;


public class MusicPlayBarView extends View {
private byte[] mBytes;
private Rect mRect = new Rect();
private Paint mForePaint = new Paint();


public MusicPlayBarView(Context context) {
super(context);
init();
}


public MusicPlayBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}


public MusicPlayBarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}


public boolean isShow() {
return super.isShown();
}


private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (!MusicPlayBarView.this.isShown())
return;

mHandler.removeMessages(0);
Random random = new Random();
byte[] bytes = getBytes(987);
if (isShow) {
bytes = getBytes(random.nextInt());
mHandler.sendEmptyMessageDelayed(0, 200);
}
updateVisualizer(bytes);
}
};


public void show() {
isShow = true;
mHandler.sendEmptyMessage(0);


}


public void hide() {
isShow = false;
mHandler.sendEmptyMessage(0);
}


private boolean isShow = false;


private byte[] getBytes(int data) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data & 0xff00) >> 8);
bytes[2] = (byte) ((data & 0xff0000) >> 16);
bytes[3] = (byte) ((data & 0xff000000) >> 24);
return bytes;
}


public static byte[] getBytes(long data) {
byte[] bytes = new byte[8];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data >> 8) & 0xff);
bytes[2] = (byte) ((data >> 16) & 0xff);
bytes[3] = (byte) ((data >> 24) & 0xff);
bytes[4] = (byte) ((data >> 32) & 0xff);
bytes[5] = (byte) ((data >> 40) & 0xff);
bytes[6] = (byte) ((data >> 48) & 0xff);
bytes[7] = (byte) ((data >> 56) & 0xff);
return bytes;
}


public byte[] getBytes(float data) {
int intBits = Float.floatToIntBits(data);
return getBytes(intBits);
}


public byte[] getBytes(double data) {
long intBits = Double.doubleToLongBits(data);
return getBytes(intBits);
}


private void init() {
mBytes = null;
mForePaint.setStrokeWidth(1f);
mForePaint.setAntiAlias(true);
mForePaint.setColor(Color.rgb(0, 143, 229));//this is play bar color
}


public void updateVisualizer(byte[] bytes) {
byte[] model = new byte[bytes.length];
for (int i = 0; i < bytes.length - 1; i++)
model[i] = bytes[i];
mBytes = bytes;
invalidate();
}


private void drawRect(float left, float width, float top, Canvas canvas) {
final float right = left + width;
final float bottom = getHeight();
final float thickness = 3.0f;
float currenttop = bottom;
while (true) {
canvas.drawRect(left, currenttop - thickness, right, currenttop,
mForePaint);
currenttop -= thickness;
// currenttop -= 1.0f;
if (currenttop <= top)
break;
}
}


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBytes == null) {
return;
}


int sum = 0;
for (int i = 0; i < mBytes.length; i++)
sum += mBytes[i];


if (sum == 0)
return;


mRect.set(0, 0, getWidth(), getHeight());
int length = mBytes.length;
final float width = getResources().getDimensionPixelSize(
R.dimen.music_play_animation_width);// play bar width
final float blankWidth = getResources().getDimensionPixelSize(
R.dimen.music_play_animation_blank_area_width);// blank area width
final float lastOffSet = width + blankWidth;
float left, top;
for (int i = 0; i < length; i++) {
left = lastOffSet * i;// every play bar start x position.
top = mRect.height() / 2 + ((byte) mBytes[i])
* (mRect.height() / 2) / 128;
drawRect(left, width, top, canvas);
}
}
}

所以如果要修改,大概就是上面3个注释的地方,然后附上参考的资源:http://download.csdn.net/detail/u010343650/9431392 音乐频谱分析把时域上连续的信号(波形)强度  

然后改简单了很多。

实现效果如下:



更新:2016-07-28 17:11

在RecyclerView中使用的时候遇到了问题,所以优化了一下代码结构:距记录下:

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;


public class MusicPlayBarView extends View {
private byte[] mBytes;
private Rect mRect = new Rect();
private Paint mForePaint = new Paint();
//this is use to RecyclerView may not reload show() and maybe the view not shown but call show()  

//添加这个标志的原因是用于判断当前是否进入循环了。如果没有则在onDraw()方法的时候进入。为什么需要这样呢。原因是RecyclerView的一个资源节约的机制来的,在item不在页面显示中的时候就会销毁掉这个View,导致无法在重新进入的时候跳动。然后就是有的时候他不会销毁,但是会暂停住整个状态,就是这个item处于第一个超出界面的item时不会销毁(个人猜测没看源码)。所以导致了滑动RecyclerView回来之后不会跳动的问题。所以添加这个用于解决此问题。
private AtomicBoolean mInHandlerFlag=new AtomicBoolean(false);


public MusicPlayBarView (Context context) {
super(context);
init();
}


public MusicPlayBarView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}


public MusicPlayBarView (Context context, AttributeSet attrs) {
super(context, attrs);
init();
}


public boolean isShow() {
return super.isShown();
}


@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mInHandlerFlag.set(false);

}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (!MusicPlayBarView .this.isShown())
return;

mHandler.removeMessages(0);
mInHandlerFlag.set(true);
Random random = new Random();
byte[] bytes = getBytes(987);

bytes = getBytes(random.nextInt());
if (isShow.get()) {
mHandler.sendEmptyMessageDelayed(0, 100);
}
updateVisualizer(bytes);
}
};


public void show() {
if (!isShow.get()) {
isShow.set(true);
mHandler.sendEmptyMessage(0);
}


}
public void hide() {
isShow.set(false);
mHandler.sendEmptyMessage(0);
}


private AtomicBoolean isShow = new AtomicBoolean(false);


private byte[] getBytes(int data) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data & 0xff00) >> 8);
bytes[2] = (byte) ((data & 0xff0000) >> 16);
bytes[3] = (byte) ((data & 0xff000000) >> 24);
return bytes;
}


public static byte[] getBytes(long data) {
byte[] bytes = new byte[8];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data >> 8) & 0xff);
bytes[2] = (byte) ((data >> 16) & 0xff);
bytes[3] = (byte) ((data >> 24) & 0xff);
bytes[4] = (byte) ((data >> 32) & 0xff);
bytes[5] = (byte) ((data >> 40) & 0xff);
bytes[6] = (byte) ((data >> 48) & 0xff);
bytes[7] = (byte) ((data >> 56) & 0xff);
return bytes;
}


public byte[] getBytes(float data) {
int intBits = Float.floatToIntBits(data);
return getBytes(intBits);
}


public byte[] getBytes(double data) {
long intBits = Double.doubleToLongBits(data);
return getBytes(intBits);
}


private void init() {
mBytes = null;
mForePaint.setStrokeWidth(1f);
mForePaint.setAntiAlias(true);
mForePaint.setColor(Color.rgb(0, 143, 229));
}


public void updateVisualizer(byte[] bytes) {
byte[] model = new byte[bytes.length];
for (int i = 0; i < bytes.length - 1; i++)
model[i] = bytes[i];
mBytes = bytes;
invalidate();
}


private void drawRect(float left, float width, float top, Canvas canvas) {
final float right = left + width;
final float bottom = getHeight();
final float thickness = 3.0f;
float currenttop = bottom;
while (true) {
canvas.drawRect(left, currenttop - thickness, right, currenttop,
mForePaint);
currenttop -= thickness;
// currenttop -= 1.0f;
if (currenttop <= top)
break;
}
}



@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isShow.get()&&!mInHandlerFlag.get()){
mHandler.sendEmptyMessage(0);
return;
}
if (mBytes == null) {
return;
}
int sum = 0;
for (int i = 0; i < mBytes.length; i++)
sum += mBytes[i];


if (sum == 0)
return;


mRect.set(0, 0, getWidth(), getHeight());
int length = mBytes.length;
final float width = getResources().getDimensionPixelSize(
R.dimen.music_play_animation_width);// play bar width
final float blankWidth = getResources().getDimensionPixelSize(
R.dimen.music_play_animation_blank_area_width);// blank area width
final float lastOffSet = width + blankWidth;
float left, top;
for (int i = 0; i < length; i++) {
left = lastOffSet * i;// every play bar start x position.
top = mRect.height() / 2 + ((byte) mBytes[i])
* (mRect.height() / 2) / 128;
drawRect(left, width, top, canvas);
}
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值