由于项目需要,需要对图表中的label设置点击事件,可是google给的包没有实现这功能。看来得靠自己了!
慢慢看源码吧~
- 关于AChartEnging的事件,使用这个组件时大致有一下几个设置:
- 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()的矩形。
由此很容易想到解决方案:
- 在x轴标签处创建相应的可点击矩形,添加到clickableAreas中即可
这样解决的方法就有很多了,比较简单的方法就是在y轴最小值下面添加一项。。。。。(由于我的图标不用提供缩放和移动,并且最小值固定为0),只要 vYalues = -5d,添加一项即可。