public class RealTimeWaveView extends SurfaceView {
private static String TAG = RealTimeWaveView.class.getSimpleName();
private SurfaceHolder surfaceHolder;
private Paint paint = new Paint();
private int width; // view width
private int height; // view height
private final int yMax = 300; // Y轴默认最大值
private BlockingQueue<Integer> queue = new LinkedBlockingDeque<>();
private ScheduledExecutorService scheduledExecutorService;
private long startDrawDelay = 3 * 1000; // 延迟 3 秒开始绘图
private float clearGap = getResources().getDimension(R.dimen.clear_gap);
private Canvas drawCanvas, clearCanvas;
private Bitmap drawBitmap, clearBitmap;
public void putData(String valuesArray) {
JSONArray jsonArray = JSON.parseArray(valuesArray);
for (int i = 0; i < jsonArray.size(); i++) {
Integer v = jsonArray.getInteger(i);
queue.offer(v);
}
}
public RealTimeWaveView(Context context) {
super(context);
init();
}
public RealTimeWaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
MyLogger.d(TAG, "surfaceCreated");
scheduledExecutorService = Executors.newScheduledThreadPool(5);
scheduledExecutorService.scheduleAtFixedRate(new DrawRunnable(), startDrawDelay, 40, TimeUnit.MILLISECONDS);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
MyLogger.d(TAG, "surfaceDestroyed");
scheduledExecutorService.shutdown();
}
});
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
MyLogger.d(TAG, "width " + width + " height " + height);
drawBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(drawBitmap);
drawCanvas.drawColor(getResources().getColor(android.R.color.black));
clearBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
clearCanvas = new Canvas(clearBitmap);
clearCanvas.drawColor(getResources().getColor(android.R.color.black));
}
class DrawRunnable implements Runnable {
float currentX = 0, currentY = height / 2.0f;
float lastX = 0, lastY = height / 2.0f;
float deltaX = (float) width / 750;
int step = 10; // 每次画几个点
private void drawOne(Canvas canvas) {
Integer value = queue.poll();
if (value == null) {
value = 0;
}
currentY = (float) value / yMax * (height / 2.0f) + (height / 2.0f);
if (currentY > height / 2.0f) {
currentY = height / 2.0f;
}
MyLogger.d(TAG, "x:" + currentX + " y:" + currentY);
canvas.drawLine(lastX, lastY, currentX, currentY, paint);
lastX = currentX;
lastY = currentY;
currentX += deltaX;
if (currentX >= width) {
currentX = 0;
// currentY = height / 2.0f;
lastX = 0;
lastY = height / 2.0f;
}
}
@Override
public void run() {
Rect rect = new Rect((int) lastX, 0, (int) (currentX + clearGap), height);
drawCanvas.drawBitmap(clearBitmap, rect, rect, paint);
for (int i = 0; i < step; i++) {
drawOne(drawCanvas);
}
Canvas canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
canvas.drawBitmap(drawBitmap, 0, 0, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
参考网上思路写的一个 demo,仅供参考
两个 Bitmap 一个作为橡皮檫在前面每次擦除一段比如 20cm,另外一个 Bitmap 在后面每次画一小段比如 15cm, 中间留一个间隔。
假如界面上始终显示 3秒的波形图,假设每一秒给你 100 个点的数据,那么我 3秒内要画 300 个数据点(1秒要画 100 个点)。
然后根据 view 的宽度就能得到每两个点的间隔 deltaX, 然后 x轴 从零开始间隔 deltaX 画一点就行了,画到头再从头循环。
我 1 秒要画 100 个点,也就是 10毫秒要画一个点(一个线段)。如果一次画一个点界面上划线速度太慢,我们可以一次画多个点(多条线段),比如我可以每次画 10 个点,要在 100毫秒内画完 10 个点(9条线段)。 然后划线时间可以用定时器控制,每隔100毫秒定时器执行一次绘制,绘制 10 个点的数据(这里忽略绘制时间,假设10个点肯定可在100毫秒内画完)。
网友评论