編輯:關於Android編程
現在在手上的是一個證券資訊類型的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
protected void drawKChatBackGround() {
Rect dirty = new Rect(left, kChartTop, right, KChartbottom);
// 畫背景圖的矩形
mCanvas.drawRect(dirty, LineGrayPaint);
PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
LineGrayPaint.setPathEffect(effects);
Path path = new Path();
int y = kChartTop + 15;
// 畫上面的虛線
path.moveTo(left, y );
path.lineTo(right, y );
String text = getPriceText(highPrice);
int textHeight = (int) (textGrayPaint.descent() - textGrayPaint.ascent());
mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2 ,textGrayPaint);
double max = highPrice - lowPrice;
if (max > 10){
// 分成四等分
// 畫中間的三根虛線
int n = 4;
double sper = (highPrice - lowPrice) / 4;// 每一等分代表的價格
for(int i=1;i<n;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 (int i = num - 1; i > 0; i--) {
int x = left + perWidth * i;
path.moveTo(x, kChartTop);
path.lineTo(x, KChartbottom);
perXPoint[i - 1] = x;
}
mCanvas.drawPath(path, LineGrayPaint);
}
@Override
protected void drawMAChart() {
// 畫均線
Path path5 = new Path();
Path path10 = new Path();
Path path20 = new Path();
double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);
int maStart = left;
float maStartY;
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 = new Paint();
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
protected void drawPillarsChart(int flag) {
LineGrayPaint.setPathEffect(null);
Rect dirty = new Rect(left, pillarsChartTop, right, pillarsChartbottom);
// 畫背景圖的矩形
mCanvas.drawRect(dirty, LineGrayPaint);
int y = pillarsChartTop + (pillarsChartbottom - pillarsChartTop)/2;
mCanvas.drawLine(left,y,right, y, LineGrayPaint);
// 中間的值
String totalCount = getPriceText(maxCount/2/10000);
float maginLeft = 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);
int pStart = left;
float pStartY;
double heightScale = (pillarsChartbottom - pillarsChartTop)/maxCount;
Paint paint = new Paint();
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 = new Rect(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 = new Rect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2);
paint.setColor(info.getColor());
// 畫背景圖的矩形
mCanvas.drawRect(dirty, paint);
pStart += per * per56;// 右邊的間距 5/6
}
}
}
/**
* 分時圖
*/
@Override
public void drawHoursChart(){
double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);
int cLeft = left;
int cTop = 0;
Path path = new Path();
path.moveTo(cLeft, KChartbottom-2);
int position = 0;
int perPointX = 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());
float textWidth = textGrayPaint.measureText(text);
int textHeight = (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 = new Paint();
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);
}
新年伊始,中國股市走出世界罕見,前無古人後無來者的極端行情,股市有風險,投資需謹慎。
這句話是題外話了,重點還是希望對大家學習Android程序設計有所幫助。
Android——滑動監聽SwipeRefreshLayout+瀑布流Recycl+Butter自動生成
package c.example.jreduch09;import android.os.AsyncTask;import android.os.Bundle;impo
使用TextPaint來繪制文字
TextPaint是paint的子類,用它可以很方便的進行文字的繪制,一般情況下遇到繪制文字的需求時,我們一般用TextPaint所提供的方法。開始學習如何繪制文字之前,
Android使用Notification實現寬視圖通知欄(二)
Notification是在你的應用常規界面之外展示的消息。當app讓系統發送一個消息的時候,消息首先以圖表的形式顯示在通知欄。要查看消息的詳情需要進入通知抽屜(noti
Android分析破解-秒脫360加固大法
Android相比iOS,安全問題往往比較突出,各種漏洞和破解層出不窮。對破解方法的了解,能在開發中進行預防,加強應用的安全性。本系列文章會對Android應用的破解和保