先說下實現的需求: 咱們須要一個x軸分爲12個刻度,x軸最大值爲24. y軸最大刻度值爲180,這樣的一個k線圖,如右圖所示canvas
x最大爲刻度24,y最大值爲180.那麼咱們怎麼去繪製x軸刻度呢? 仔細想一想,x軸分爲12份,最大值24.而且k線圖表的寬度是已知的,那麼咱們等比例計算: xStep(一個刻度)=已知寬度/24。 不就能夠知道一個刻度值是多少了麼?api
那咱們再來分析分析y軸的怎麼處理。數組
如今已知的數值:最大值180,圖表的高度(ps:別糾結圖表高寬怎麼來的啊~會挨板子的。控件生命週期onLayout 哪裏就能夠獲取了) 那麼 參考x軸的計算方式,同樣咱們能夠經過:yStep=已知高度/180.是否是挺簡單的啊。至於駝峯,留到文末再說。有了思路,那麼代碼實現起來就很容易了,寫這篇簡易文章的出發點是想跟你們說說本身日常的我的觀點,不要什麼場景、事物開始前都想着直接找輪子,本身嘗試實現、摸索的過程對於我的是y頗有益的。咳咳咳,很差意思。我跑題了。 回到原點,接下來開始編碼部分:bash
繼承View 重寫onLayout 獲取已知高寬markdown
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getWidth();
height = getHeight();
}
複製代碼
按照上面分析的公式,繪製X軸刻度ide
xPaint = new Paint(); xPaint.setAntiAlias(true); xPaint.setStrokeWidth(xlinewidth); xPaint.setStrokeCap(Paint.Cap.ROUND); xPaint.setColor(xlinecolor); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); step = width / 24f; y_step = height / 180f; canvas.drawLine(0, height, width, height, xPaint); for (int i = 0; i <= 12; i++) { canvas.drawLine((i * 2) * step, 0, (i * 2) * step, height, xPaint); } } 複製代碼
知道刻度步伐,實現軸刻度是否是簡單多了。 接下來咱們繪製k線吧。 我有一個24長度的集合數據:編碼
ArrayList<Integer> data = new ArrayList<>();
data.add(10);
data.add(50);
data.add(100);
data.add(40);
data.add(120);
data.add(60);
data.add(80);
data.add(160);
data.add(90);
data.add(80);
data.add(60);
data.add(40);
data.add(20);
data.add(50);
data.add(80);
data.add(100);
data.add(130);
data.add(160);
data.add(180);
data.add(50);
data.add(120);
data.add(100);
data.add(80);
data.add(60);
data.add(10);
複製代碼
集合的角標分別對應x軸的1-24,我想把他們體如今圖標上。那要怎麼作呢? 其實想一想,咱們已知xStep和yStep,那麼不久能夠知道每一個值在每一個刻度的x,y座標了麼? 如 data集合0角標:x座標=xStep1 y座標=yStep10(data集合0角標的值)。 繪製一個點須要x,y就足夠了。 那麼咱們的實現邏輯代碼以下:spa
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); step = width / 24f; y_step = height / 180f; canvas.drawLine(0, height, width, height, xPaint); for (int i = 0; i <= 12; i++) { canvas.drawLine((i * 2) * step, 0, (i * 2) * step, height, xPaint); } Path path = new Path(); path.moveTo(0, height); for (int i = 0; i < data.size(); i++) { float x = (i + 1) * step; //這是x座標 float y = height - (data.get(i) * y_step);//這是y座標 總高度-y座標,是爲了從下往上 path.lineTo(x, y); } canvas.drawPath(path, linePaint); } 複製代碼
到了這一步是否是感受特別簡單啊,那麼恭喜你,又收穫了自定義綜合使用路上的小小知識點。畢竟水滴石穿嘛。 言歸正傳,咱們還有最後一個步驟,渲染駝峯呢~~~ 這一步我就不羅嗦了,官方其實有提供api的,小火雞們日常要多查查看看文檔啊(LinearGradient)code
mPaintShader = new Paint(); mPaintShader.setAntiAlias(true); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); step = width / 24f; y_step = height / 180f; canvas.drawLine(0, height, width, height, xPaint); for (int i = 0; i <= 12; i++) { canvas.drawLine((i * 2) * step, 0, (i * 2) * step, height, xPaint); } //繪製折線 Path path = new Path(); path.moveTo(0, height); for (int i = 0; i < data.size(); i++) { float x = (i + 1) * step; //這是x座標 float y = height - (data.get(i) * y_step);//這是y座標 總高度-y座標,是爲了從下往上 path.lineTo(x, y); } path.lineTo(width, height); canvas.drawPath(path, linePaint); Shader mShader = new LinearGradient(0, height + 10, 0, 0, getResources().getColor(R.color.colorAccent1), getResources().getColor(R.color.colorAccent5), Shader.TileMode.REPEAT); //新建一個線性漸變,前兩個參數是漸變開始的點座標,第三四個參數是漸變結束的點的座標。鏈接這2個點就拉出一條漸變線了, // 。而後那個數組是漸變的顏色。下一個參數是漸變顏色的分佈,若是爲空,每一個顏色就是均勻分佈的。最後是模式,這裏設置的是循環漸變 mPaintShader.setShader(mShader); canvas.drawPath(path, mPaintShader); } 複製代碼
回過頭看看,這一切實現起來不麻煩吧,只要日常多分析分析,碰到需求能夠適當嘗試一下本身實現,畢竟技術進階之路不是一味的搬輪子~~不喜勿碰orm