行情K線圖也就是我們常說的燭炬圖,是金融類軟件里可以說必不可少的,不管日K, 周K,月K,還是分鐘K,準確的來表達個股在1定時間內漲跌走勢,K線圖有著不可疏忽的作用,其繪制進程也是彰顯1個程序員對自定義控件的熟練程度,特別是對Canvas的靈活應用,繪線,繪邊框,及位置的選取,比例的分配,今天這個Demo,則1步步為你詮釋。
按慣例,先看下今天要實現的效果,全部Demo地址為:http://download.csdn.net/detail/ming_147/9732963,也能夠關注公眾號后(評論區(qū)第1條評論掃描便可)回復“行情k線圖”,源碼就會發(fā)送給您,公眾號有很多android及其它技術文章,還請大家承蒙關注。
相對來講比較簡單的1個小Demo,為何來講簡單呢,1數據是固定的,2,時間是固定的,相比較實際項目中來講,這已相當的簡單了,我們可以簡單的分1下步驟模塊,然后再依照順次來進行實現,通過上面的圖片,我們可以大致分為,邊框,橫線,縱線,底部時間,左側刻度,柱狀圖(燭炬圖),10字光標這幾個部份,好,分好以后,我們就來1步步實現吧。
由于代碼稍多,為顯得代碼結構清晰,我們可以先寫1個父類,用于實現邊框,橫縱線,及底部時間,左部刻度的繪制,柱狀圖(燭炬圖)及10字光標我們放在子類中實現。
自定義1個父類繼承于View,實現其構造方法,在onMeasure方法里設置View的大小:
@Override
protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
private int measureWidth(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);//得到模式
int specSize = MeasureSpec.getSize(measureSpec);//得到尺寸
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
return result;
}
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
return result;
}
這里簡單對兩個類型做下解釋:
MeasureSpec.EXACTLY是精確尺寸,當我們將控件的layout_width或layout_height指定為具體數值時如:andorid:layout_width="50dip",或為FILL_PARENT是,都是控件大小已肯定的情況,都是精確尺寸。
MeasureSpec.AT_MOST是最大尺寸,當控件的layout_width或layout_height指定為WRAP_CONTENT時,控件大小1般隨著控件的子空間或內容進行變化,此時控件尺寸只要不超過父控件允許的最大尺寸便可。因此,此時的mode是AT_MOST,size給出了父控件允許的最大尺寸。
設置完大小以后,我們先在構造方法里初始化1些信息,比如背風景,畫筆:
/**
* 設置背風景及初始化畫筆
*/
private void init() {
setBackgroundColor(Color.parseColor("#222222"));
mPaint = new Paint();
mPaint.setStrokeWidth(1);
mPaint.setStyle(Paint.Style.STROKE);
}
重寫onDraw方法,并在方法內繪制相干信息。繪制邊框,距離左上各位10,距離右側為View寬度-10,距離底部為View高度-50:
private void drawBorder(Canvas canvas) {
mPaint.setColor(Color.WHITE);
Rect r = new Rect();
r.left = 10;
r.top = 10;
r.right = this.getRight() - 10;
r.bottom = this.getHeight() - 50;
canvas.drawRect(r, mPaint);
}
繪制橫線,由于要留出1段區(qū)域做刻度繪制,所以,距離左側要有1段距離,這里我設置的100,所以每條橫線的起始位置1定,都是100,由于邊框的最右側為View寬度-10,所以橫線的終止位置也是1致,起始y的位置和終止y的位置應當1致,依照1定的距離等分開來,這里的lineSize是要分成幾份,我定義的是4份,則每份的長度就為:(當前View的高度-距離底部的距離-距離上部的距離)/lineXSize:
private int lineXSize = 4;
private void drawXLine(Canvas canvas) {
mPaint.setColor(Color.WHITE);
float height = (this.getHeight() - 10f - 50f)
/ lineXSize;//平均分為幾分
for (int a = 0; a
< lineXSize; a++) {
float h = height * a + 10f;
Log.i("BaseLine", h + "===");
canvas.drawLine(100f, h, this.getRight()
- 10f, h, mPaint);
}
}
繪制縱線,其原理和繪制橫線差不多,起始x的位置為距離左側的距離既100,則每份的寬度就是,(當前View的寬度-距離左側的距離-距離右側的距離)/要分為幾份,這里我定義的是lineYSize=3:
private int lineYSize = 3;
private void drawYLine(Canvas canvas) {
mPaint.setColor(Color.WHITE);
float width = (this.getRight() - 10f - 100f)
/ lineYSize;
for (int a = 0; a < lineYSize; a++)
{
float w = width * a + 100f;
canvas.drawLine(w, 10f, w,
this.getHeight() - 50f, mPaint);
}
}
繪制底部時間,times是自己定義的1個時間數組,其坐標位置和縱線類似,y值是固定不變的,x軸增加的距離和縱線1致:
private int[] times = {5, 6, 7, 8};
private void drawTimes(Canvas canvas) {
mPaint.setColor(Color.parseColor("#FF00FF"));
mPaint.setTextSize(24);
float width = (this.getRight() - 10f - 100f)
/ lineYSize;
for (int a = 0; a < lineYSize + 1; a++)
{
float w = width * a + 100f;
if (a == lineYSize) {
canvas.drawText(times[a] + "月", w
- 30f, this.getHeight() - 25f, mPaint);
} else {
canvas.drawText(times[a] + "月", w
- 15f, this.getHeight() - 25f, mPaint);
}
}
}
繪制Y軸價格刻度,價格刻度的繪制,就和繪制橫線有點類似了,price是自己定義的1個刻度數組:
private float[] price = {260f, 240f, 220f};
private void drawYPrice(Canvas canvas) {
mPaint.setColor(Color.WHITE);
float height = (this.getHeight() - 10f - 50f)
/ lineXSize;//平均分為幾分
for (int a = 1; a
< lineXSize; a++) {
float h = height * a + 10f;
canvas.drawText(price[a - 1] + "", 40f, h, mPaint);
}
}
經過以上父 類中的繪制,基本的邊框,橫線,縱線,底部時間,左部價格刻度,就完成了,接下來就是柱狀圖和10字光標:
自定義1個view集成于父類,實現其構造方法,初始化1些信息,設置畫筆為實心的:
private void init() {
mPaint = new Paint();
mPaint.setStrokeWidth(1);
mPaint.setStyle(Paint.Style.FILL);
}
繪制燭炬圖之前,我們需要初始化1些我們需要的數據,這里我定義了1個javaBean,里面我定義了1些數據,開盤,收盤,最高,最低,日期,實現其構造方法和get,set方法。
/**
* 開盤價
*/
private float open;
/**
* 最高價
*/
private float high;
/**
* 最低價
*/
private float low;
/**
* 收盤價
*/
private float close;
/**
* 日期
*/
private int date;
javaBean實現以后,我們就能夠添加摹擬數據了,畢竟不是真實的項目中,所以數據,只能自己去創(chuàng)造了,listData是自己定義存儲數據的:
protected List<StockLineBean> listData = new ArrayList<>();
/**
* 添加數據
*/
private void setLineData() {
List<StockLineBean> list = new ArrayList<StockLineBean>();
list.add(new StockLineBean(250, 251, 248, 250, 20170731));
list.add(new StockLineBean(249, 252, 248, 252, 20170730));
list.add(new StockLineBean(250, 251, 248, 250, 20170729));
list.add(new StockLineBean(249, 252, 248, 252, 20170728));
list.add(new StockLineBean(248, 250, 247, 250, 20170727));
list.add(new StockLineBean(256, 256, 248, 248, 20170726));
list.add(new StockLineBean(257, 258, 256, 257, 20170725));
list.add(new StockLineBean(259, 260, 256, 256, 20170724));
list.add(new StockLineBean(261, 261, 257, 259, 20170723));
list.add(new StockLineBean(259, 260, 256, 256, 20170722));
list.add(new StockLineBean(261, 261, 257, 259, 20170721));
list.add(new StockLineBean(260, 260, 259, 259, 20170720));
list.add(new StockLineBean(262, 262, 260, 261, 20170719));
list.add(new StockLineBean(260, 262, 259, 262, 20170718));
list.add(new StockLineBean(
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈