[UPDATE] 为了总结这个问题,我使用以下两种方法实现了我的图形(请参阅下文)。 drawCurve()
收到Canvas
和float
的数组。该数组已被正确填充(时间戳由数组中的值索引承担)并从0.0到1.0变化。该阵列被发送到prepareWindowArray()
,其以循环方式从位置windowStart
获取windowSize
值的数组的块。Android中的自定义动态图形
GraphView和数据提供者(蓝牙设备)使用的数组是相同的。中间的类确保GraphView不读取蓝牙设备正在写入的数据。由于GraphView始终通过阵列循环并在每次迭代时重新绘制,它将根据蓝牙设备写入的数据进行更新,并且通过强制蓝牙设备的写入频率达到Graph的刷新频率,我获得了平滑我的信号动画。
的GraphView
的invalidate()
方法由Activity
,其运行一个Timer
刷新图形在每个x
毫秒调用。图形刷新的频率是动态设置的,以便它适应来自蓝牙设备的数据流(指定其信息包头中的信号频率)。
在我在下面写的答案(答案部分)中找到我的GraphView
的完整代码。如果你们发现错误或优化方法,请告诉我;这将不胜感激!
/**
* Read a buffer array of size greater than "windowSize" and create a window array out of it.
* A curve is then drawn from this array using "windowSize" points, from left
* to right.
* @param canvas is a Canvas object on which the curve will be drawn. Ensure the canvas is the
* later drawn object at its position or you will not see your curve.
* @param data is a float array of length > windowSize. The floats must range between 0.0 and 1.0.
* A value of 0.0 will be drawn at the bottom of the graph, while a value of 1.0 will be drawn at
* the top of the graph. The range is not tested, so you must ensure to pass proper values, or your
* graph will look terrible.
* 0.0 : draw at the bottom of the graph
* 0.5 : draw in the middle of the graph
* 1.0 : draw at the top of the graph
*/
private void drawCurve(Canvas canvas, float[] data){
// Create a reference value to determine the stepping between each points to be drawn
float incrementX = (mRightSide-mLeftSide)/(float) windowSize;
float incrementY = (mBottomSide - mTopSide);
// Prepare the array for the graph
float[] source = prepareWindowArray(data);
// Prepare the curve Path
curve = new Path();
// Move at the first point.
curve.moveTo(mLeftSide, source[0]*incrementY);
// Draw the remaining points of the curve
for(int i = 1; i < windowSize; i++){
curve.lineTo(mLeftSide + (i*incrementX), source[i] * incrementY);
}
canvas.drawPath(curve, curvePaint);
}
的prepareWindowArray()
方法实现阵列的圆形行为:
/**
* Extract a window array from the data array, and reposition the windowStart
* index for next iteration
* @param data the array of data from which we get the window
* @return an array of float that represent the window
*/
private float[] prepareWindowArray(float[] data){
// Prepare the source array for the graph.
float[] source = new float[windowSize];
// Copy the window from the data array into the source array
for(int i = 0; i < windowSize; i++){
if(windowStart+i < data.length) // If the windows holds within the data array
source[i] = data[windowStart + i]; // Simply copy the value in the source array
else{ // If the window goes beyond the data array
source[i] = data[(windowStart + 1)%data.length]; // Loop at the beginning of the data array and copy from there
}
}
// Reposition the buffer index
windowStart = windowStart + windowSize;
// If the index is beyond the end of the array
if(windowStart >= data.length){
windowStart = windowStart % data.length;
}
return source;
}
[/ UPDATE]
我正在一个应用程序,在从蓝牙设备读取的数据固定利率。每当我有新的数据时,我都希望它们被绘制在右侧的图上,并将图的其余部分实时转换到左侧。基本上,就像示波器一样。
所以我用xy轴做了一个自定义视图,标题和单位。要做到这一点,我只需在视图画布上绘制这些东西。现在我想绘制曲线。我设法使用这种方法从已填充的阵列中绘制出一条静态曲线:
public void drawCurve(Canvas canvas){
int left = getPaddingLeft();
int bottom = getHeight()-getPaddingTop();
int middle = (bottom-10)/2 - 10;
curvePaint = new Paint();
curvePaint.setColor(Color.GREEN);
curvePaint.setStrokeWidth(1f);
curvePaint.setDither(true);
curvePaint.setStyle(Paint.Style.STROKE);
curvePaint.setStrokeJoin(Paint.Join.ROUND);
curvePaint.setStrokeCap(Paint.Cap.ROUND);
curvePaint.setPathEffect(new CornerPathEffect(10));
curvePaint.setAntiAlias(true);
mCurve = new Path();
mCurve.moveTo(left, middle);
for(int i = 0; i < mData[0].length; i++)
mCurve.lineTo(left + ((float)mData[0][i] * 5), middle-((float)mData[1][i] * 20));
canvas.drawPath(mCurve, curvePaint);
}
它给了我类似这样的东西。
还有事情要解决我的图形(副轴不能正常缩放),但这些都是细节,我可以稍后再修正。
现在我想要改变这个静态图(它接收一个非动态矩阵的值),并且每隔40ms重新绘制一条曲线,将旧数据向左推并将新数据绘制到右侧,所以我可以实时查看蓝牙设备提供的信息。
我知道有一些图形包已经存在了,但我对这些东西有点小事,我想通过自己实现这个图来实践。此外,我的大部分GraphView类都已完成,曲线部分除外。
第二个问题,我想知道我应该如何将新值发送给图。我应该使用像FIFO堆栈这样的东西,还是可以用简单的双倍矩阵来实现我想要的功能?
在旁注上,底部的4个字段已经动态更新。那么,他们有点伪装“动态”,他们一次又一次地通过同一个双重矩阵,他们实际上并没有采取新的价值。
谢谢你的时间!如果有关于我的问题的内容不清楚,请告诉我,我会通过更多细节进行更新。
你能给所有项目链接吗?这看起来很有趣! –