上圖
說到android的折線圖,我就必須要說一下關於繪製view的幾個重要的工具,Canvas(畫布),Paint(畫筆),Path(路徑)。
Canvas顧名思義就是用來作畫的板子或者說是布。沒有它就算有了畫筆也是無從下手。當然我們可以通過Canvas的各種屬性來設置Canvas,例如:
canvas.drawColor(Color.BLACK);//設置背景顏色爲黑色
其他設置就自己去查看api了,這裏不多講了。
Paint畫筆,用來作畫的筆,不管我們在畫布上面繪製什麼,都離不開畫筆,只要用到canvas的地方請帶上畫筆。和畫布一樣,畫筆也可以設計他獨特的屬性,例如顏色呀,粗細呀虛實線呀什麼的,這裏也不多說了。
Path路徑,就像是我們小學時候用的尺子一樣,如果要畫一條直線就得沿着尺子的邊緣話,這就是路徑的功能,不過這裏的路徑沒有那麼必須,簡單的線還是可以直接用paint畫出來的,畫折線圖用到path的地方主要是畫虛線,其實我也不是很明白爲何必須用path,不過如果直接用paint+PathEffect+座標來畫畫出來就永遠是直線了,大概因爲虛線是一節節的畫的吧。
上面簡單的介紹了一下用到的工具,下面就講講我畫折線圖的一些思路吧。
首先,一個座標圖必然要有原點座標,X,Y軸,繪製折線的基線表格,最後就是折線啦。
原點可以自己定義繪製在任何地方,我這裏由於不知道手機屏幕的具體大小,怕繪製出來比較雞肋,於是做了個屏幕自適應:
原點X座標=邊距(也就是距離邊界的寬度,android的像素點是從屏幕的左上角開始的)
原點Y座標 = 屏幕的高度 - 邊距
X軸的長度 = 屏幕寬度 - 2*邊距
Y軸的長度 = 屏幕高度 - 2*邊距
X軸的單位長度 = (屏幕寬度 - 2 * 邊距) / (X軸所顯示的標線數 - 1);
Y軸的單位長度 = (屏幕高度 - 2* 邊距 )/(Y軸所顯示的標線數 - 1)
畫圖的時候各個點座標的計算方法是:
Y軸座標 = (Y軸的單位長度 /(Y軸1點顯示的數字 - 原點Y軸顯示的數字))*(數據的Y軸數據-原點數字)
X軸同理
這樣整個折線圖的畫法就很清晰啦。下面直接上代碼
// 畫表格 private void drawTable(Canvas canvas) { Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.GRAY); Path path = new Path(); PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1); paint.setPathEffect(effects); // 縱向線 for (int i = 1; i * Xscale <= (this.getWidth() - this.Margin); i++) { int startX = Xpoint + i * Xscale; int startY = Ypoint; int stopY = Ypoint - (this.Ylabel.length - 1) * Yscale; path.moveTo(startX, startY); path.lineTo(startX, stopY); canvas.drawPath(path, paint); } // 橫向線 for (int i = 1; (Ypoint - i * Yscale) >= this.Margin; i++) { int startX = Xpoint; int startY = Ypoint - i * Yscale; int stopX = Xpoint + (this.Xlabel.length - 1) * Xscale; path.moveTo(startX, startY); path.lineTo(stopX, startY); paint.setColor(Color.DKGRAY); canvas.drawPath(path, paint); paint.setColor(Color.WHITE); paint.setTextSize(this.Margin / 2); canvas.drawText(this.Ylabel[i], this.Margin / 4, startY + this.Margin / 4, paint); } }
// 畫橫縱軸 private void drawXLine(Canvas canvas, Paint p) { canvas.drawLine(Xpoint, Ypoint, this.Margin, this.Margin, p); canvas.drawLine(Xpoint, this.Margin, Xpoint - Xpoint / 3, this.Margin + this.Margin / 3, p); canvas.drawLine(Xpoint, this.Margin, Xpoint + Xpoint / 3, this.Margin + this.Margin / 3, p); } private void drawYLine(Canvas canvas, Paint p) { canvas.drawLine(Xpoint, Ypoint, this.getWidth() - this.Margin, Ypoint, p); canvas.drawLine(this.getWidth() - this.Margin, Ypoint, this.getWidth() - this.Margin - this.Margin / 3, Ypoint - this.Margin / 3, p); canvas.drawLine(this.getWidth() - this.Margin, Ypoint, this.getWidth() - this.Margin - this.Margin / 3, Ypoint + this.Margin / 3, p); }
// 畫數據 private void drawData(Canvas canvas) { Paint p = new Paint(); p.setAntiAlias(true); p.setColor(Color.WHITE); p.setTextSize(this.Margin / 2); // 縱向線 for (int i = 1; i * Xscale <= (this.getWidth() - this.Margin); i++) { int startX = Xpoint + i * Xscale; canvas.drawText(this.Xlabel[i], startX - this.Margin / 4, this.getHeight() - this.Margin / 4, p); canvas.drawCircle(startX, calY(Data[i]), 4, p); canvas.drawLine(Xpoint+(i-1)*Xscale, calY(Data[i-1]), startX, calY(Data[i]), p); } } /** * * @param y * @return */ private int calY(int y){ int y0 = 0 ; int y1 = 0 ; try{ y0 = Integer.parseInt(Ylabel[0]); y1 = Integer.parseInt(Ylabel[1]); }catch(Exception e){ return 0; } try{ return Ypoint-((y-y0)*Yscale/(y1-y0)) ; }catch(Exception e){ return 0; } }
最後不要忘了
@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.BLACK); Paint p1 = new Paint(); p1.setStyle(Paint.Style.STROKE); p1.setAntiAlias(true); p1.setColor(Color.WHITE); p1.setStrokeWidth(2); init(); this.drawXLine(canvas, p1); this.drawYLine(canvas, p1); this.drawTable(canvas); this.drawData(canvas); }
完整項目的代碼在下面,有興趣的可以自己下載來玩玩