現在在手上的是一個證券資訊類型的app,其中有涉及到股票行情界面,行情中有K線圖等,看到網上很多人在求這方面的資料,所以我特地寫了一個demo在此處給大家分享一下。
下面是做出來的效果圖:
這個 界面 是如何畫出來的我就不做介紹了,大家可以去下載項目源碼。
背景圖是利用canvas先畫出一個矩形,然后再畫幾根虛線,均線圖是通過path來繪制的,總之圖的繪制是很簡單的,我就不在這里作介紹了,大家可以去github下載源碼看看。涉及到均線、最高價、最低價、收盤價、開盤價的概念大家可以百度一下。
我再這里要介紹的是計算問題:
大家可以看到分時圖、日K、月K的左邊的成交價格都是不一樣的,而我們的k線都是通過這個價格來繪制的,也就是說價格是時刻變動,那么我們的k線繪制也是變動的。假設我們要計算分時圖中價格為25.69的那一分鍾應該如何畫,畫在屏幕中的哪一個位置,那么這個應該怎么畫呢,價格是變動的,畫的位置也是變動的,但是有一點我們屏幕的大小是不變的。所以我們可以通過背景圖的高度來計算某個價格的線圖應該從哪個地方開始畫。我們可以計算出一個像素點對應多少個價格,分析圖如下:
價格和像素形成個一個比例計算是:double heightScale = (endY - startY)/(highPrice - lowPrice);
所以價格25.69應該是畫在mStartY = (float) (startY+ (highPrice - 25.69) * heightScale);
這個明白了之后其他的原理都是一樣的,我就不介紹了,下面是部分代碼:
@Override
protectedvoiddrawKChatBackGround() {
Rect dirty = newRect(left, kChartTop, right, KChartbottom);
// 畫背景圖的矩形
mCanvas.drawRect(dirty, LineGrayPaint);
PathEffect effects = newDashPathEffect(newfloat[] {5,5,5,5},1);
LineGrayPaint.setPathEffect(effects);
Path path = newPath();
inty = kChartTop +15;
// 畫上面的虛線
path.moveTo(left, y );
path.lineTo(right, y );
String text = getPriceText(highPrice);
inttextHeight = (int) (textGrayPaint.descent() - textGrayPaint.ascent());
mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);
doublemax = highPrice - lowPrice;
if(max >10){
// 分成四等分
// 畫中間的三根虛線
intn =4;
doublesper = (highPrice - lowPrice) /4;// 每一等分代表的價格
for(inti=1;i
y = i*((KChartbottom - kChartTop)/n) + kChartTop;
path.moveTo(left, y);
path.lineTo(right,y);
text = getPriceText(highPrice - i*sper);
mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);
}
}else{
// 分成兩等分
// 畫中間的虛線
y = (KChartbottom - kChartTop)/2+ kChartTop;
path.moveTo(left, y);
path.lineTo(right, y);
text = getPriceText(highPrice - (highPrice - lowPrice) / 2);
mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);
}
// 畫下面的虛線
y = KChartbottom - 15;
path.moveTo(left, y);
path.lineTo(right, y);
text = getPriceText(lowPrice);
mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);
// // 畫等分的虛線和下面的日期
for(inti = num -1; i >0; i--) {
intx = left + perWidth * i;
path.moveTo(x, kChartTop);
path.lineTo(x, KChartbottom);
perXPoint[i - 1] = x;
}
mCanvas.drawPath(path, LineGrayPaint);
}
@Override
protectedvoiddrawMAChart() {
// 畫均線
Path path5 = newPath();
Path path10 = newPath();
Path path20 = newPath();
doubleheightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);
intmaStart = left;
floatmaStartY;
path5.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue5()) * heightScale));
path10.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue10()) * heightScale));
path20.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue20()) * heightScale));
for(SingleStockInfo info:infos){
maStart += per * perHalf;// 每一天實際所占的數據是4/6,左右邊距各1/6
maStartY = (float) (kChartTop + (highPrice - info.getMaValue5()) * heightScale);
path5.lineTo(maStart, maStartY);
maStartY = (float) (kChartTop + (highPrice - info.getMaValue10()) * heightScale);
path10.lineTo(maStart, maStartY);
maStartY = (float) (kChartTop + (highPrice - info.getMaValue20()) * heightScale);
path20.lineTo(maStart, maStartY);
maStart += per * perHalf;
}
Paint paint = newPaint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStyle(Style.STROKE);
mCanvas.drawPath(path5, paint);
paint.setColor(Color.MAGENTA);
mCanvas.drawPath(path10, paint);
paint.setColor(Color.GREEN);
mCanvas.drawPath(path20, paint);
}
/**
* 下面的柱形圖
*/
@Override
protectedvoiddrawPillarsChart(intflag) {
LineGrayPaint.setPathEffect(null);
Rect dirty = newRect(left, pillarsChartTop, right, pillarsChartbottom);
// 畫背景圖的矩形
mCanvas.drawRect(dirty, LineGrayPaint);
inty = pillarsChartTop + (pillarsChartbottom - pillarsChartTop)/2;
mCanvas.drawLine(left,y,right, y, LineGrayPaint);
// 中間的值
String totalCount = getPriceText(maxCount/2/10000);
floatmaginLeft = left - textGrayPaint.measureText(totalCount)-5;
mCanvas.drawText(totalCount, maginLeft, y,textGrayPaint);
// 上面的值
totalCount = getPriceText(maxCount/10000);
maginLeft = left - textGrayPaint.measureText(totalCount)- 5;
mCanvas.drawText(totalCount, maginLeft, pillarsChartTop,textGrayPaint);
// 下面的值
totalCount = "萬手";
maginLeft = left - textGrayPaint.measureText(totalCount) - 5;
mCanvas.drawText(totalCount, maginLeft, pillarsChartbottom,textGrayPaint);
intpStart = left;
floatpStartY;
doubleheightScale = (pillarsChartbottom - pillarsChartTop)/maxCount;
Paint paint = newPaint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
if(flag == StockService.FLAG){
for(MinuteInfo info:minuteInfos){
pStart += per * per16;// 每一天實際所占的數據是4/6,加上1/6
pStartY = (float) (pillarsChartTop + (maxCount - info.getVolume()) * heightScale);
dirty = newRect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2);
paint.setColor(info.getColor());
// 畫背景圖的矩形
mCanvas.drawRect(dirty, paint);
pStart += per * per56;// 右邊的間距 5/6
}
}else{
for(SingleStockInfo info:infos){
pStart += per * per16;// 每一天實際所占的數據是4/6,加上1/6
pStartY = (float) (pillarsChartTop + (maxCount - info.getTotalCount()) * heightScale);
dirty = newRect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2);
paint.setColor(info.getColor());
// 畫背景圖的矩形
mCanvas.drawRect(dirty, paint);
pStart += per * per56;// 右邊的間距 5/6
}
}
}
/**
* 分時圖
*/
@Override
publicvoiddrawHoursChart(){
doubleheightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);
intcLeft = left;
intcTop =0;
Path path = newPath();
path.moveTo(cLeft, KChartbottom-2);
intposition =0;
intperPointX = perXPoint[position];// 記錄第一條垂直虛線的x坐標
for(MinuteInfo info:minuteInfos){
cLeft += per * per16;
cTop = (int) (kChartTop + (highPrice - info.getNow()) * heightScale);
path.lineTo(cLeft + per * per26, cTop);
if(cLeft >= perPointX){
// 恰好畫到第一條垂直虛線的地方,需要畫下面的時間
String text = KChartUtil.getMinute(info.getMinute());
floattextWidth = textGrayPaint.measureText(text);
inttextHeight = (int) (textGrayPaint.descent()- textGrayPaint.ascent());
mCanvas.drawText(text, perPointX - textWidth/2, KChartbottom + textHeight, textGrayPaint);
if(!(position == perXPoint.length-1)){
Log.e(TAG, perPointX+"----------"+info.getMinute()+"---"+text);
perPointX = perXPoint[++position];
}
}
cLeft += per * per56;// 右邊的間距 5/6
}
path.lineTo(cLeft, KChartbottom-2);
Paint LinePaint = newPaint();
LinePaint.setColor(Color.BLUE);
LinePaint.setAntiAlias(true);
LinePaint.setStrokeWidth(1);
LinePaint.setStyle(Style.STROKE);
// LinePaint.setStyle(Style.STROKE);
mCanvas.drawPath(path, LinePaint);
LinePaint.setAlpha(50);
LinePaint.setStyle(Style.FILL);
mCanvas.drawPath(path, LinePaint);
}
demo鏈接:
https://github.com/chuanlongwu/kChart4Android