先贴上MPAndroidChart 的GitHub上地址:https://github.com/PhilJay/MPAndroidChart
RadarChart的使用这里不做介绍,如有需要请自行查阅!
直奔主题,查看RadarChart的监听方法,仅仅提供了OnChartValueSelectedListener方法,改方法仅能作用于图形上的点击事件,并不能实现lable点击事件(及RadarChart的x轴点击事件),所以需要自己实现其方法;
想要实现lable点击事件,我们可以实现RadarChart的setOnTouchListener()方法,从触摸的位置判断点击区域是否在RadarChart的文字区域,查看RadarChat源码,发现RadarChat的lable绘制主要依靠XAxisRendererRadarChart类实现,
其中drawLable方法则是调用MPAndroidChart中的Util方法
参照其源码的实现方式,可以计算每个lable的绘制区域Rect及起始绘制点,
/**
* 计算位置
* @param compositeRadar
* @return
*/
public static List computePosition(RadarChart compositeRadar) {
List pointBeans = new ArrayList<>();
XAxis xAxis = compositeRadar.getXAxis();
final float labelRotationAngleDegrees = xAxis.getLabelRotationAngle();
final MPPointF drawLabelAnchor = MPPointF.getInstance(0.5f, 0.25f);
float sliceangle = compositeRadar.getSliceAngle();
float factor = compositeRadar.getFactor();
MPPointF center = compositeRadar.getCenterOffsets();
MPPointF pOut = MPPointF.getInstance(0, 0);
for (int i = 0; i < compositeRadar.getData().getMaxEntryCountSet().getEntryCount(); i++) {
String label = xAxis.getValueFormatter().getFormattedValue(i, xAxis);
float angle = (sliceangle * i + compositeRadar.getRotationAngle()) % 360f;
Utils.getPosition(center, compositeRadar.getYRange() * factor
+ xAxis.mLabelRotatedWidth / 2f, angle, pOut);
pointBeans.add(computeStartPoint(label, pOut.x, pOut.y - xAxis.mLabelRotatedHeight / 2.f,
mAxisLabelPaint, drawLabelAnchor, labelRotationAngleDegrees));
}
return pointBeans;
}
computeStartPoint方法:
/**
* 计算文字绘制起点
* @param text
* @param x
* @param y
* @param paint
* @param anchor
* @param angleDegrees
* @return
*/
private static RadarPointBean computeStartPoint(String text, float x, float y,
Paint paint,
MPPointF anchor, float angleDegrees) {
mDrawTextRectBuffer = new Rect();
mFontMetricsBuffer = new Paint.FontMetrics();
float drawOffsetX = 0.f;
float drawOffsetY = 0.f;
final float lineHeight = paint.getFontMetrics(mFontMetricsBuffer);
paint.getTextBounds(text, 0, text.length(), mDrawTextRectBuffer);
drawOffsetX -= mDrawTextRectBuffer.left;
drawOffsetY += -mFontMetricsBuffer.ascent;
if (angleDegrees != 0.f) {
drawOffsetX -= mDrawTextRectBuffer.width() * 0.5f;
drawOffsetY -= lineHeight * 0.5f;
} else {
if (anchor.x != 0.f || anchor.y != 0.f) {
drawOffsetX -= mDrawTextRectBuffer.width() * anchor.x;
drawOffsetY -= lineHeight * anchor.y;
}
drawOffsetX += x;
drawOffsetY += y;
}
return new RadarPointBean(drawOffsetX, drawOffsetY, mDrawTextRectBuffer);
}
其中RadarPointBean为保存每个lable的起始点及Rect,其属性为:
public class RadarPointBean {
float startX;
float startY;
Rect rect;
public RadarPointBean(float startX, float startY, Rect rect) {
this.startX = startX;
this.startY = startY;
this.rect = rect;
}
}
这里需要一个mAxisLabelPaint,继续查看,mAxisLabelPaint是AxisRenderer中的属性,
然而RadarChart中有mXAxisRenderer属性,
并且XAxisRendererRadarChart继承与XAxisRenderer,
因此只要回去到RadarChart中的,便能够获取到Paint,但是mXAxisRenderer是protected属性,而且RadarChart中没有提供外部调用方法,我们可以通过反射或者定义RadarChart子类的方法获取到XAxisRendererChart,这里我采用反射获取,从效率来讲,定义RadarChart子类比反射获取更好;
/**
* 反射获取XAxisRendererRadarChart
* @param compositeRadar
* @return
*/
private static XAxisRendererRadarChart getXAxisRendererRadarChart(RadarChart compositeRadar) {
try {
Field field = compositeRadar.getClass().getDeclaredField("mXAxisRenderer");
field.setAccessible(true);
XAxisRendererRadarChart mXAxisRenderer = (XAxisRendererRadarChart) field.get(compositeRadar);
return mXAxisRenderer;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
然后修改computePosition方法:
/**
* 计算位置
* @param compositeRadar
* @return
*/
public static List computePosition(RadarChart compositeRadar) {
List pointBeans = new ArrayList<>();
XAxis xAxis = compositeRadar.getXAxis();
final float labelRotationAngleDegrees = xAxis.getLabelRotationAngle();
final MPPointF drawLabelAnchor = MPPointF.getInstance(0.5f, 0.25f);
XAxisRendererRadarChart mXAxisRenderer = getXAxisRendererRadarChart(compositeRadar);
float sliceangle = compositeRadar.getSliceAngle();
float factor = compositeRadar.getFactor();
MPPointF center = compositeRadar.getCenterOffsets();
MPPointF pOut = MPPointF.getInstance(0, 0);
for (int i = 0; i < compositeRadar.getData().getMaxEntryCountSet().getEntryCount(); i++) {
String label = xAxis.getValueFormatter().getFormattedValue(i, xAxis);
float angle = (sliceangle * i + compositeRadar.getRotationAngle()) % 360f;
Utils.getPosition(center, compositeRadar.getYRange() * factor
+ xAxis.mLabelRotatedWidth / 2f, angle, pOut);
pointBeans.add(computeStartPoint(label, pOut.x, pOut.y - xAxis.mLabelRotatedHeight / 2.f,
mXAxisRenderer.getPaintAxisLabels(), drawLabelAnchor, labelRotationAngleDegrees));
}
return pointBeans;
}
这样便获取到了每个lable的绘制起点及绘制区域,然后添加事件:
float x = 0;//临时保存点击坐标
float y = 0;//临时保存点击坐标
compositeRadar.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
List pointBeans = RadarUtil.computePosition(compositeRadar);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
break;
case MotionEvent.ACTION_UP:
for (int i = 0; i < pointBeans.size(); i++) {
RadarPointBean pointBean = pointBeans.get(i);
if (pointBean.isIn(x, y)) {
if (radarDatas != null && radarDatas.size() >= i) {
ToastUtils.showShort("点击第" + i + "个lable");
LogUtils.i("点击第" + i + "个lable");
StudentDimensionBean bean = radarDatas.get(i);
gotoCompositeDetail(bean);
}
return true;
}
}
break;
default:
break;
}
return false;
}
});
RadarPointBean中的isIn方法为:
private static final int DEF_PADDING = 25;//为文字增加点击区域 相当于padding
public boolean isIn(float x, float y) {
float endX = startX + Math.abs(rect.right - rect.left) + DEF_PADDING;
float endY = startY - Math.abs(rect.bottom - rect.top) - DEF_PADDING;
float startX = getStartX() - DEF_PADDING;
float startY = getStartY() + DEF_PADDING;
return startX < x && x < endX && startY > y && y > endY;
}
获取XAxisRendererRadarChart从效率上建议使用定义RadarChart子类方式:
public class CustomRadarChart extends RadarChart {
public CustomRadarChart(Context context) {
super(context);
}
public XAxisRendererRadarChart getXAxisRenderer(){
return mXAxisRenderer;
}
}
如有其它更好的方法,欢迎探讨.
demo地址:戳这里