目錄
基於MPAndroidChart庫製作K線圖(一) —— 基礎圖
基於MPAndroidChart庫製作K線圖(二) —— 自定義x、y軸
基於MPAndroidChart庫製作K線圖(三) —— 手勢高亮聯動
最近製作一個炒幣的app,類似於炒股的那種,網上資料很多很雜,最後使用github上面的MPAndroidChart庫基本實現了功能。
一、介紹
MPAndroidChart庫:https://github.com/PhilJay/MPAndroidChart
1.1支持圖形
- Line Chart 折線圖
- Bar Chart 直方圖
- Pie Chart 餅圖
- Bubble Chart 氣泡圖
- Candle Stick Chart 蠟燭圖(用於展示金融數據時常稱爲K線圖)
- Radar Chart 雷達圖
- Cubic Line Chart 立方折線圖
- Stacked Bar Chart 堆積圖
1.2MPAndroid使用
- Project level build.gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
- App level build.gradle
dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
}
二、基礎實現效果圖
三、核心代碼
3.1、初始化表格
主要的一些屬性均已寫註釋,部分註釋可能有所偏差,具體以MPAndroidChart源碼註釋爲準
private void initChart() {
//K線
ccKl.setNoDataTextColor(getResources().getColor(R.color.gray8B));//無數據時提示文字的顏色
ccKl.setDescription(null);//取消描述
ccKl.getLegend().setEnabled(false);//取消圖例
ccKl.setDragDecelerationEnabled(false);//不允許甩動慣性滑動 和moveView方法有衝突 設置爲false
ccKl.setMinOffset(0);//設置外邊緣偏移量
ccKl.setExtraBottomOffset(6);//設置底部外邊緣偏移量 便於顯示X軸
ccKl.setScaleEnabled(false);//不可縮放
ccKl.setAutoScaleMinMaxEnabled(true);//自適應最大最小值
ccKl.setDrawOrder(new CombinedChart.DrawOrder[]{CombinedChart.DrawOrder.CANDLE, CombinedChart.DrawOrder.LINE}); //繪製順序,先繪製條形再繪製條線
//K線 x軸
XAxis xac = ccKl.getXAxis();
xac.setPosition(XAxis.XAxisPosition.BOTTOM);
xac.setGridColor(getResources().getColor(R.color.black3B));//網格線顏色
xac.setTextColor(getResources().getColor(R.color.gray8B));//標籤顏色
xac.setTextSize(8);//標籤字體大小
xac.setAxisLineColor(getResources().getColor(R.color.black3B));//軸線顏色
xac.disableAxisLineDashedLine();//取消軸線虛線設置
xac.setAvoidFirstLastClipping(true);//避免首尾端標籤被裁剪
xac.setLabelCount(5, true);//強制顯示2個標籤
//K線 左Y軸
YAxis axisLeft = ccKl.getAxisLeft();
axisLeft.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART); //標籤顯示在內側;OUTSIDE_CHART外側
axisLeft.setGridColor(getResources().getColor(R.color.black3B)); //網格顏色
axisLeft.setTextColor(getResources().getColor(R.color.gray8B)); //文字顏色
axisLeft.setTextSize(8); //文字大小
axisLeft.setLabelCount(5, true); //label個數,強制設置標籤計數
axisLeft.enableGridDashedLine(5, 4, 0);//橫向網格線設置爲虛線
//K線 右Y軸
YAxis axisRight = ccKl.getAxisRight();
axisRight.setEnabled(false); //不繪製右軸
//蠟燭圖
candleSet = new CandleDataSet(new ArrayList<CandleEntry>(), "Kline");
candleSet.setAxisDependency(YAxis.AxisDependency.LEFT);
candleSet.setDrawHorizontalHighlightIndicator(false);
candleSet.setHighlightLineWidth(0.5f);
candleSet.setHighLightColor(getResources().getColor(R.color.brown));
candleSet.setShadowWidth(0.7f);
candleSet.setIncreasingColor(getResources().getColor(R.color.redEB)); //上漲設置爲紅色
candleSet.setIncreasingPaintStyle(Paint.Style.FILL); //fill:實心填充 stroke:空心描邊 fill_and_stroke 填充描邊
candleSet.setDecreasingColor(getResources().getColor(R.color.green4C));//下跌設置爲綠色
candleSet.setDecreasingPaintStyle(Paint.Style.FILL); //fill:實心填充 stroke:空心描邊 fill_and_stroke 填充描邊
candleSet.setNeutralColor(getResources().getColor(R.color.redEB));
candleSet.setShadowColorSameAsCandle(true);
candleSet.setDrawValues(false);
candleSet.setHighlightEnabled(false);
//5分均線
lineSet5 = new LineDataSet(new ArrayList<Entry>(), "MA5");
lineSet5.setAxisDependency(YAxis.AxisDependency.LEFT);
lineSet5.setColor(getResources().getColor(R.color.purple));
lineSet5.setDrawCircles(false);
lineSet5.setDrawValues(false);
lineSet5.setHighlightEnabled(false);
//10分均線
lineSet10 = new LineDataSet(new ArrayList<Entry>(), "MA10");
lineSet10.setAxisDependency(YAxis.AxisDependency.LEFT);
lineSet10.setColor(getResources().getColor(R.color.yellow));
lineSet10.setDrawCircles(false);
lineSet10.setDrawValues(false);
lineSet10.setHighlightEnabled(false);
//30分均線
lineSet30 = new LineDataSet(new ArrayList<Entry>(), "MA30");
lineSet30.setAxisDependency(YAxis.AxisDependency.LEFT);
lineSet30.setColor(getResources().getColor(R.color.white));
lineSet30.setDrawCircles(false);
lineSet30.setDrawValues(false);
lineSet30.setHighlightEnabled(false);
//分時線
lineSetMin = new LineDataSet(new ArrayList<Entry>(), "Minutes");
lineSetMin.setAxisDependency(YAxis.AxisDependency.LEFT);
lineSetMin.setColor(Color.WHITE);
lineSetMin.setDrawCircles(false);
lineSetMin.setDrawValues(false);
lineSetMin.setDrawFilled(true);
lineSetMin.setHighlightEnabled(false);
lineSetMin.setFillColor(getResources().getColor(R.color.gray8B));
lineSetMin.setFillAlpha(60);
//成交量
bcKl.setNoDataTextColor(getResources().getColor(R.color.gray8B));
bcKl.setDescription(null);
bcKl.getLegend().setEnabled(false);
bcKl.setDragDecelerationEnabled(false); //不允許甩動慣性滑動
bcKl.setMinOffset(0); //設置外邊緣偏移量
bcKl.setScaleEnabled(false);//不可縮放
bcKl.setAutoScaleMinMaxEnabled(true);//自適應最大最小值
//x軸
XAxis xAxis = bcKl.getXAxis();
xAxis.setEnabled(false);
//左Y軸
YAxis axisLeft1 = bcKl.getAxisLeft();
axisLeft1.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);//標籤顯示在內側
axisLeft1.setDrawAxisLine(false);
axisLeft1.setGridColor(getResources().getColor(R.color.black3B));
axisLeft1.setTextColor(getResources().getColor(R.color.gray8B));
axisLeft1.setTextSize(8);
axisLeft1.setLabelCount(2, true);
axisLeft1.setAxisMinimum(0);
//右Y軸
YAxis axisRight1 = bcKl.getAxisRight();
axisRight1.setEnabled(false); //不繪製右軸
//柱狀圖
barSet = new BarDataSet(new ArrayList<BarEntry>(), "VOL");
barSet.setHighLightColor(getResources().getColor(R.color.brown));
barSet.setColors(getResources().getColor(R.color.redEB), getResources().getColor(R.color.green4C));
barSet.setDrawValues(false);
barSet.setHighlightEnabled(false);
}
3.2、數據來源以及設置數據
簡要描述:
- 獲取k線數據
請求URL:
https://openapi.dragonex.io/api/v1/market/kline/
請求方式:
- GET
參數:
字段名 | 數據類型 | 說明 |
---|---|---|
symbol_id | int | 交易對ID |
st | int | 起始時間,從當前時間開始時可不傳或傳0,否則傳unix時間戳(納秒) |
direction | int | 查詢方向:1 -從起始時間往後查,2 -從起始時間往前查,默認2 |
count | int | 查詢條數,最大100,默認10 |
kline_type | int | k線類型:1 -1min線, 2 -5min線, 3 -15min線, 4 -30min線, 5 -60min線, 6 -1day線.默認1 |
返回示例
返回值data信息:
字段名 | 數據類型 | 說明 |
---|---|---|
columns | [] | 下述列表每個位置的數據代表的意義 |
list | [] | kline數據 |
list信息:
字段名 | 數據類型 | 說明 |
---|---|---|
amount | string | 交易額 |
close_price | string | 收盤價 |
max_price | string | 最高價 |
min_price | string | 最低價 |
open_price | string | 開盤價 |
pre_close_price | string | 上一個收盤價 |
timestamp | int | 秒級時間戳 |
usdt_amount | string | 對應的USDT交易額 |
volume | string | 交易量 |
{
"ok": true,
"code": 1,
"msg": "",
"data": {
"columns": [
"amount",
"close_price",
"max_price",
"min_price",
"open_price",
"pre_close_price",
"timestamp",
"usdt_amount",
"volume"
],
"lists": [
[
"28413.7359",
"289.0131",
"290.7236",
"288.9502",
"289.9977",
"0.0000",
1536075900,
"28413.7359",
"98.0704"
],
[
"17430.8759",
"289.1027",
"290.3000",
"288.9529",
"289.0229",
"0.0000",
1536076800,
"17430.8759",
"60.3029"
],
......
[
"3812.4130",
"254.9381",
"255.6408",
"254.9335",
"254.9436",
"0.0000",
1536165000,
"3812.4130",
"14.9540"
]
]
}
}
- 設置數據
private void configData() {
if (combinedData == null) {
combinedData = new CombinedData();
}
xValues.clear();
List<CandleEntry> candleValues = candleSet.getValues();
candleValues.clear();
List<Entry> ma5Values = lineSet5.getValues();
ma5Values.clear();
List<Entry> ma10Values = lineSet10.getValues();
ma10Values.clear();
List<Entry> ma30Values = lineSet30.getValues();
ma30Values.clear();
List<Entry> minValues = lineSetMin.getValues();
minValues.clear();
List<BarEntry> barValues = barSet.getValues();
barValues.clear();
for (int i = 0; i < dataList.size(); i++) {
List<String> k = dataList.get(i);
Date d = new Date(Long.parseLong(k.get(6)) * 1000); //6.毫秒
String x = sdf.format(d); //顯示日期
if (xValues.containsValue(x)) { //x重複
dataList.remove(i);
i--;
} else {
xValues.put(i, x);
float open = Float.parseFloat(k.get(4)); //4.open
float close = Float.parseFloat(k.get(1)); //1.close
candleValues.add(new CandleEntry(i, Float.parseFloat(k.get(2)), Float.parseFloat(k.get(3)), open, close, x)); //2.max 3.min
minValues.add(new Entry(i, close, x));
barValues.add(new BarEntry(i, Float.parseFloat(k.get(8)), close >= open ? 0 : 1)); //8.volume交易量
if (i >= 4) {
ma5Values.add(new Entry(i, getMA(i, 5)));
if (i >= 9) {
ma10Values.add(new Entry(i, getMA(i, 10)));
if (i >= 29) {
ma30Values.add(new Entry(i, getMA(i, 30)));
}
}
}
}
}
candleSet.setValues(candleValues);
lineSet5.setValues(ma5Values);
lineSet10.setValues(ma10Values);
lineSet30.setValues(ma30Values);
lineSetMin.setValues(minValues);
if (tlKl.getSelectedTabPosition() == 0) {
combinedData.removeDataSet(candleSet); //分時圖時移除蠟燭圖
combinedData.setData(new LineData(lineSetMin)); //分時線
} else {
combinedData.setData(new CandleData(candleSet)); //蠟燭圖
combinedData.setData(new LineData(lineSet5, lineSet10, lineSet30)); //5分線 10分線 30分線
}
ccKl.setData(combinedData);
float xMax = xValues.size() - 0.5F; //默認X軸最大值是 xValues.size() - 1
ccKl.getXAxis().setAxisMaximum(xMax); //使最後一個顯示完整
barSet.setValues(barValues);
BarData barData = new BarData(barSet);
barData.setBarWidth(1 - candleSet.getBarSpace() * 2);//使Candle和Bar寬度一致
bcKl.setData(barData);
bcKl.getXAxis().setAxisMaximum(xMax + (-0.5f));//保持邊緣對齊
ccKl.setVisibleXRange(52, 52);//設置顯示X軸個數的上下限,豎屏固定52個
bcKl.setVisibleXRange(52, 52);
}
四、源碼下載
github: https://github.com/xkdaq/KoinChart
coding: https://coding.net/u/xkdaq/p/KoinChart/git (最新代碼在coding上)