目录
使用MPAndroidChart实现K线图(1)——基本用法
使用MPAndroidChart实现K线图(2)——自定义XY轴
使用MPAndroidChart实现K线图(3)——自定义柱状图
使用MPAndroidChart实现K线图(4)——图表联动、加载更多
使用MPAndroidChart实现K线图(5)——高亮联动、横竖屏切换
MPAndroidChart中的X轴和Y轴的标签内容,可以调用setValueFormatter(IAxisValueFormatter f)方法,对不同的value返回不同的显示内容,如下所示:
xac.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
int v = (int) value;
if (!xValues.containsKey(v) && xValues.containsKey(v - 1)) {
v = v - 1;
}
String x = xValues.get(v);
return TextUtils.isEmpty(x) ? "" : x;
}
});
(说明:不想显示的标签一定要返回空字符串,不要返回null,因为MPAndroidChart的后续代码会调用返回值的一些方法,而null会出现空指针异常。)
但是标签的位置以及颜色等信息,都是轴的渲染器AxisRenderer控制的,特别是标签位置,在源码中是固定的,想要改变只能自定义渲染器。
X轴的标签,我们想要的效果是:第一个标签右移显示完整,与边缘有一定间隔,最后一个标签左移显示完整,与边缘有一定间隔,其他标签不变。由XAxisRenderer的源码可知,标签的绘制在drawLabels(Canvas c, float pos, MPPointF anchor)方法中,且第一个标签已经向右平移。接下来要做的就是,自定义渲染器InBoundXAxisRenderer,继承XAxisRenderer,重写drawLabels()方法。
protected int interval;
@Override
protected void drawLabels(Canvas c, float pos, MPPointF anchor) {
final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
boolean centeringEnabled = mXAxis.isCenterAxisLabelsEnabled();
float[] positions = new float[mXAxis.mEntryCount * 2];
for (int i = 0; i < positions.length; i += 2) {
// only fill x values
if (centeringEnabled) {
positions[i] = mXAxis.mCenteredEntries[i / 2];
} else {
positions[i] = mXAxis.mEntries[i / 2];
}
}
mTrans.pointValuesToPixel(positions);
for (int i = 0; i < positions.length; i += 2) {
float x = positions[i];
if (mViewPortHandler.isInBoundsX(x)) {
String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis);
if (mXAxis.isAvoidFirstLastClippingEnabled()) {
// avoid clipping of the last
float width = Utils.calcTextWidth(mAxisLabelPaint, label);
if (i == mXAxis.mEntryCount * 2 - 2 && mXAxis.mEntryCount > 1) {
x -= width / 2 + interval;
// avoid clipping of the first
} else if (i == 0) {
x += width / 2 + interval;
}
}
drawLabel(c, label, x, pos, anchor, labelRotationAngleDegrees);
}
}
}
只修改了两处:一处是,第一个标签i=0时,对x加一个间隔interval;另一处是,最后一个标签i为最后一个时,x向左平移一半以及一个间隔interval。
接着把这个渲染器设置给CombinedChart(因BarChart已取消X轴显示,所以不需设置), 其中的间隔interval,在创建时传入。
Transformer trans = cc.getTransformer(YAxis.AxisDependency.LEFT);
//自定义X轴标签位置
cc.setXAxisRenderer(new InBoundXAxisRenderer(cc.getViewPortHandler(), cc.getXAxis(), trans, 10));
Y轴的标签,我们想要的效果是:最上方的一个标签,平移到当前y值的下方,其余标签平移到当前y值的上方。由YAxisRenderer的源码可知,标签的绘制在drawYLabels(Canvas c, float fixedPosition, float[] positions, float offset)方法中,且传入了偏移量offset,在renderAxisLabels(Canvas c)方法中调用了这个方法,其中:
float yoffset = Utils.calcTextHeight(mAxisLabelPaint, "A") / 2.5f + mYAxis.getYOffset();
可见,标签的Y值多加了1/2.5(即0.4)个文字高度。因此,自定义渲染器InBoundYAxisRenderer,继承YAxisRenderer,重写drawYLabels()方法,在此基础上继续平移即可。
@Override
protected void drawYLabels(Canvas c, float fixedPosition, float[] positions, float offset) {
final int from = mYAxis.isDrawBottomYLabelEntryEnabled() ? 0 : 1;
final int to = mYAxis.isDrawTopYLabelEntryEnabled() ? mYAxis.mEntryCount : (mYAxis.mEntryCount - 1);
// draw
int labelHeight = Utils.calcTextHeight(mAxisLabelPaint, "A");
for (int i = from; i < to; i++) {
String text = mYAxis.getFormattedLabel(i);
float os = i == mYAxis.mEntryCount - 1 ? -0.9F * labelHeight : 0.7F * labelHeight;
c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset - os, mAxisLabelPaint);
}
}
只修改了一处,最后一个标签继续向下平移0.9个文字高度(预留部分间隙),其余标签继续向上平移0.7个文字高度。
接着把这个渲染器设置给CombinedChart和BarChart。
Transformer trans = cc.getTransformer(YAxis.AxisDependency.LEFT);
//自定义Y轴标签位置
cc.setRendererLeftYAxis(new InBoundYAxisRenderer(cc.getViewPortHandler(), cc.getAxisLeft(), trans));
//自定义Y轴标签位置
bc.setRendererLeftYAxis(new InBoundYAxisRenderer(bc.getViewPortHandler(), bc.getAxisLeft(),
bc.getTransformer(YAxis.AxisDependency.LEFT)));
运行程序,绘制效果图如下:
X轴和Y轴的标签位置已达到预期。
关于Render的理解:
渲染器Render是用来控制绘制的类,轴用来控制标签(Label)、网格线(GridLine)、轴线(ZeroLine)、限制线(LimitLine)等的位置和颜色,以及其他的绘制功能;图表用来控制数据(Data)、值(Value)、高亮(Highlighted)、附加信息(Extra)等的绘制。其中,轴的标签内容虽然也可以在Render中控制,但不建议这样做,因为已经提供了自定义标签内容的方法setValueFormatter(),不建议在自定义类中重复已提供的功能。后续图表的一些功能,都是在自定义Render情况下实现的。
下一步要做的是:
自定义BarChart的Render,使Bar的颜色与红涨绿跌对应,且绘制柱状图时向左平移0.5个单位,与上部分的K线对齐。
完整demo地址:https://github.com/ShallowBillow/KlineDemo