由于项目需要,需要对图表中的label设置点击事件,可是google给的包没有实现这功能。看来得靠自己了!
慢慢看源码吧~
renderer.setPanEnabled(true, false);//表盘移动 renderer.setPanEnabled(true, false);//表盘缩放 renderer.setClickEnabled(true);//是否可点击 renderer.setSelectableBuffer(20);//点击区域大小
用起来是很方便的,但在源码中实现还是比较复杂的,特别是移动和缩放功能,先暂不讨论。
下面是在XYChart中点击某个点,触发事件的使用方法:
class ChartViewClick implements View.OnClickListener { @Override public void onClick(View v) { GraphicalView graphicalView = (GraphicalView) v; //获取当前点击点 SeriesSelection seriesSelection = graphicalView.getCurrentSeriesAndPoint(); if (seriesSelection == null) { return; } int x = (int) seriesSelection.getXValue(); Toast.makeText(context, "第几个点" + x, Toast.LENGTH_SHORT).show(); } }
public SeriesSelection getCurrentSeriesAndPoint() { return mChart.getSeriesAndPointForScreenCoordinate(new Point(oldX, oldY)); }
oldx,oldy应该就是触控事件中获取的
@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // save the x and y so they can be used in the click and long press // listeners oldX = event.getX(); oldY = event.getY(); } if (mRenderer != null && (mRenderer.isPanEnabled() || mRenderer.isZoomEnabled())) { if (mTouchHandler.handleTouch(event)) { return true; } } return super.onTouchEvent(event); }
查看源码,发现getCurrentSeriesAndPoint()在抽象类AbstractChart.java中,XYChart重写了:
public SeriesSelection getSeriesAndPointForScreenCoordinate(final Point screenPoint) { if (clickableAreas != null) for (int seriesIndex = clickableAreas.size() - 1; seriesIndex >= 0; seriesIndex--) { // series 0 is drawn first. Then series 1 is drawn on top, and series 2 // on top of that. // we want to know what the user clicked on, so traverse them in the // order they appear on the screen. int pointIndex = 0; if (clickableAreas.get(seriesIndex) != null) { RectF rectangle; for (ClickableArea area : clickableAreas.get(seriesIndex)) { rectangle = area.getRect(); if (rectangle != null && rectangle.contains(screenPoint.getX(), screenPoint.getY())) { return new SeriesSelection(seriesIndex, pointIndex, area.getX(), area.getY()); } pointIndex++; } } } return super.getSeriesAndPointForScreenCoordinate(screenPoint); }
看来,关键在于clickableAreas的构造了。这在XYChart的onDraw方法中,差不多有100行
... clickableAreas = new HashMap<Integer, List<ClickableArea>>(); //sLength = series.size();遍历几条线 for (int i = 0; i < sLength; i++) { ... //遍历线中的每个点 for (Entry<Double, Double> value : range.entrySet()) { ... values.add(value.getKey()); values.add(value.getValue()); //把坐标值转换成屏幕中像素坐标 if (!isNullValue(yValue)) { points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale]))); points.add((float) (bottom - yPixelsPerUnit[scale] * (yValue - minY[scale]))); ... //关键的来了,生成点击区域 ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints( MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i, startIndex); ... } clickableAreas.put(i, clickableArea); //clickableAreas是一个域,保存所有可点击系列 } }
查看上面clickableAreasForPoints方法,发现其实就是在坐标像素点处建一个变长为render.getSelectableBuffer()的矩形。
由此很容易想到解决方案:
这样解决的方法就有很多了,比较简单的方法就是在y轴最小值下面添加一项。。。。。(由于我的图标不用提供缩放和移动,并且最小值固定为0),只要 vYalues = -5d,添加一项即可。