最近制作一个炒币的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); //不绘制右轴
axisRight.setDrawLabels(false); //不绘制右轴标签
axisRight.setDrawGridLines(false); //不绘制网格
axisRight.setDrawAxisLine(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);//自适应最大最小值
//自定义Y轴标签位置
bcKl.setRendererLeftYAxis(new InBoundYAxisRenderer(bcKl.getViewPortHandler(), bcKl.getAxisLeft(),
bcKl.getTransformer(YAxis.AxisDependency.LEFT)));
//设置渲染器控制颜色、偏移,以及高亮
bcKl.setRenderer(new OffsetBarRenderer(bcKl, bcKl.getAnimator(), bcKl.getViewPortHandler(), -0.5f)
.setHighlightWidthSize(0.5f, CommentUtil.sp2px(this, 8)));
//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);
axisLeft1.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return value == 0 ? "" : value + "";
}
});
//右Y轴
YAxis axisRight1 = bcKl.getAxisRight();
//axisRight1.setEnabled(false); //不绘制右轴
axisRight1.setDrawLabels(false); //不绘制右轴标签
axisRight1.setDrawGridLines(false); //不绘制网格
axisRight1.setDrawAxisLine(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、数据来源以及设置数据
设置数据
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);
}
四、源码下载