[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個字段已經動態更新。那麼,他們有點僞裝「動態」,他們一次又一次地通過同一個雙重矩陣,他們實際上並沒有採取新的價值。
謝謝你的時間!如果有關於我的問題的內容不清楚,請告訴我,我會通過更多細節進行更新。
你能給所有項目鏈接嗎?這看起來很有趣! –