認識觀和Canvas
首先,應該研究從Android官方文檔Canvas and Drawables Guide。尤其值得注意的是,LineChart
,BarChart
等是View
的子類,它們通過覆蓋View超類的onDraw(Canvas c)
回調來顯示它們自己。還要注意「畫布」的定義:
畫布對你來說是作爲你的圖形繪製的實際表面的僞裝或界面 - 它包含你所有的「繪製」調用。
當您使用渲染器時,您將處理在畫布上繪製線條等的功能。
畫布圖表上
點被指定爲x和y的值相對於所述圖表上的單位對所述圖表上的值和像素之間的翻譯。例如,在下面的圖表中,第一欄的中心位於x = 0
。第一欄的y值爲52.28
。
這顯然不對應於畫布上的像素座標。在畫布上,畫布上的x = 0
將是最左邊的像素,它們顯然是空白的。同樣,由於像素枚舉從頂部開始爲y = 0
,因此柱形的頂端顯然不是52.28
(圖表上的y值)。如果我們使用開發人員選項/指針位置,我們可以看到第一個小節的提示大約爲x = 165
和y = 1150
。
A Transformer
負責將圖表值轉換爲像素(屏幕上)座標,反之亦然。渲染器中的一種常見模式是使用圖表值(更易於理解)執行計算,然後在最後使用變換器將變換應用於屏幕上。
查看端口和邊界
視圖端口是一個窗口,即,在圖表上的有界區域。視圖端口用於確定用戶當前可以看到哪部分圖表。每個圖表都有一個ViewPortHandler
,它封裝了與視圖端口相關的功能。我們可以使用ViewPortHandler#isInBoundsLeft(float x)
isInBoundsRight(float x)
來確定用戶當前可以看到哪些x值。
在上圖所示的圖表中,BarChart「知道」爲6或更高,但由於它們超出界限而不在當前視口中,因此不會呈現6和向上。因此,x值0
到5
在當前視口內。
ChartAnimator
的ChartAnimator
提供要被施加到該圖表的額外轉化。通常這是一個簡單的乘法。例如,假設我們需要一個動畫,其中圖表的點從底部開始並逐漸上升到正確的y值超過1秒。動畫師將提供一個phaseY
,這是一個簡單的標量,從0.000
開始,時間爲0ms
,並且逐漸上升到1.000
,1000ms
。
現在
我們理解所涉及的基本概念的渲染代碼的例子,讓我們來看看一些代碼LineChartRenderer
:
protected void drawHorizontalBezier(ILineDataSet dataSet) {
float phaseY = mAnimator.getPhaseY();
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
mXBounds.set(mChart, dataSet);
cubicPath.reset();
if (mXBounds.range >= 1) {
Entry prev = dataSet.getEntryForIndex(mXBounds.min);
Entry cur = prev;
// let the spline start
cubicPath.moveTo(cur.getX(), cur.getY() * phaseY);
for (int j = mXBounds.min + 1; j <= mXBounds.range + mXBounds.min; j++) {
prev = cur;
cur = dataSet.getEntryForIndex(j);
final float cpx = (prev.getX())
+ (cur.getX() - prev.getX())/2.0f;
cubicPath.cubicTo(
cpx, prev.getY() * phaseY,
cpx, cur.getY() * phaseY,
cur.getX(), cur.getY() * phaseY);
}
}
// if filled is enabled, close the path
if (dataSet.isDrawFilledEnabled()) {
cubicFillPath.reset();
cubicFillPath.addPath(cubicPath);
// create a new path, this is bad for performance
drawCubicFill(mBitmapCanvas, dataSet, cubicFillPath, trans, mXBounds);
}
mRenderPaint.setColor(dataSet.getColor());
mRenderPaint.setStyle(Paint.Style.STROKE);
trans.pathValueToPixel(cubicPath);
mBitmapCanvas.drawPath(cubicPath, mRenderPaint);
mRenderPaint.setPathEffect(null);
}
的for
循環之前的前幾行是設置爲渲染器循環。請注意,我們從ChartAnimator(變換器)獲得phaseY
,並計算視圖端口邊界。
for
循環的基本含義是「對於位於視口左右邊界內的每個點」。呈現無法看到的x值沒有意義。
在循環中,我們使用dataSet.getEntryForIndex(j)
獲取當前條目的x值和y值,並在該條和前一條目之間創建一條路徑。請注意路徑全部乘以phaseY
的動畫。
最後,之後已計算出的路徑的變換被施加trans.pathValueToPixel(cubicPath);
和路徑被渲染到畫布mBitmapCanvas.drawPath(cubicPath, mRenderPaint);
編寫自定義渲染
的第一步是選擇正確類子類。請注意包com.github.mikephil.charting.renderer
中的類 ,包括XAxisRenderer
和LineChartRenderer
等。一旦創建了子類,就可以簡單地覆蓋相應的方法。根據上面的示例代碼,我們將覆蓋void drawHorizontalBezier(ILineDataSet dataSet)
而不調用super
(以便不會調用渲染階段兩次)並將其替換爲我們想要的功能。如果你這樣做是正確的,重寫的方法至少應該有點像你覆蓋方法:
- 變壓器,動畫師獲得一個手柄,和界限
- 通過可見性×循環 - 值(將x值是視口範圍內的是)
- 準備個圖表呈現值
- 轉化點爲像素的畫布
- 上的使用
Canvas
類方法繪製在畫布上
您應該研究Canvas class(drawBitmap
等)中的方法,以查看允許您在渲染器循環中執行哪些操作。
如果您需要覆蓋的方法未公開,您可能必須繼承像LineRadarRenderer
這樣的基礎渲染器才能實現所需的功能。
一旦你設計了你想要的渲染器子類,你可以用Chart#setRenderer(DataRenderer renderer)
或BarLineChartBase#setXAxisRenderer(XAxisRenderer renderer)
或其他方法輕鬆地使用它。