前言
今天给大家介绍下Highlight。
Highlight相关属性
/**
* the x-value of the highlighted value
*/
private float mX = Float.NaN;
/**
* the y-value of the highlighted value
*/
private float mY = Float.NaN;
/**
* the x-pixel of the highlight
*/
private float mXPx;
/**
* the y-pixel of the highlight
*/
private float mYPx;
/**
* the index of the data object - in case it refers to more than one
*/
private int mDataIndex = -1;
/**
* the index of the dataset the highlighted value is in
*/
private int mDataSetIndex;
/**
* index which value of a stacked bar entry is highlighted, default -1
*/
private int mStackIndex = -1;
/**
* the axis the highlighted value belongs to
*/
private YAxis.AxisDependency axis;
/**
* the x-position (pixels) on which this highlight object was last drawn
*/
private float mDrawX;
/**
* the y-position (pixels) on which this highlight object was last drawn
*/
private float mDrawY;
光看一堆代码,没意思哈。直接上图:
上图是 MPAndroidChart Example 中的LinechartActivity1的截图。我们可以看到,有一个十字交叉线,十字交叉的地方就是图中的数据点,说明已经Highlight选中了这个点。
我们来看下这张图对应的Highlight的属性的值是多少:
mX = 7,mY = 67.5
mXPx = mX 对应的屏幕坐标的px值 mYPx = mY 对应的屏幕坐标的px值
mDataSetIndex = 0 (只有一条线)
axis = AxisDependency.LEFT
mDrawX = mXPx (最后一次的画过的X坐标)
mDrawY = mYPx (最后一次的画过的Y坐标)
下面是我的小项目中的的一个截图,找找有什么不一样啊?
不同点一:十字线的交叉点是鼠标或者说是手指触摸的点。
刚开始做的时候,没注意到这点,因为有两条线,一个是分时线(蓝色),一个是均线(黄色),如果选中了某一个点,那么会有两条横着的Highlight线,这样就不美观了。再仔细对照了下设计图,十字交叉的地方是手指触摸的地方。那有啥办法,硬着头皮改源码。首先弄清Highlight每个属性的含义,然后找到对应的画Highlight线的地方,改下就好了。这个还是蛮简单的。
不同点二:有多条折线,折线与竖直的线重合的点会有个小圆点标记。
这些个小圆点也是要自己动手在原来基础上添加。
不同点三:有MarkerView,也就是我之后要和大家介绍的。
不同点四:有两个Y轴,横轴是时间轴,不是从0开始。
刚开始我曾想过,时间作为横轴的话,在new Entry(x,y)的时候x传时间,y传值。可仔细一看,x是Int类型,没有重载的String类型。那怎么办?看了他内部实现才知道,数据创建了之后,整个Chart的移动,拖拽,放大,等操作,都是通过Matrix实现的。Matrix总不可能拿着一个时间去操作吧。后面一想,只要数据点和对应的时间对应上就好了。比如9点30分对应第一个数据点。这样就能一一找到每个点对应的时间值了。
画HightLight线
假设我们是在做出长按事件后,画出高亮线的。如何实现呢?来看看源码吧。
首先找突破点,长按事件与事件监听有关,我们找到了BarLineChartTouchListener类。发现里面有个重载方法:
@Override
public void onLongPress(MotionEvent e) {
mLastGesture = ChartGesture.LONG_PRESS;
OnChartGestureListener l = mChart.getOnChartGestureListener();
if (l != null) {
l.onChartLongPressed(e);
}
Highlight h = mChart.getHighlightByTouchPoint(e.getX(), e.getY());
performHighlight(h, e);
mChart.disableScroll();
}
这就是长按事件的监听,长按事件触发后,获取手指触摸的地方对应的Highlight,然后调用performHighlight(h, e)方法:
protected void performHighlight(Highlight h, MotionEvent e) {
if (h == null || h.equalTo(mLastHighlighted)) {
mChart.highlightValue(null, true);
mLastHighlighted = null;
} else {
mChart.highlightValue(h, true);
mLastHighlighted = h;
}
}
从中,我们看到了,方法中调用了highlightValue(h, true)方法,继续跟踪:
/**
* Highlights the value selected by touch gesture. Unlike
* highlightValues(...), this generates a callback to the
* OnChartValueSelectedListener.
* @param high - the highlight object
* @param callListener - call the listener
*/
public void highlightValue(Highlight high, boolean callListener) {
Entry e = null;
if (high == null)
mIndicesToHighlight = null;
else {
if (mLogEnabled)
Log.i(LOG_TAG, "Highlighted: " + high.toString());
long start = System.currentTimeMillis();
e = mData.getEntryForHighlight(high);
long stop = System.currentTimeMillis();
if (mLogEnabled)
Log.i(LOG_TAG, "Highlighted: " + (stop-start)+"ms");
if (e == null) {
mIndicesToHighlight = null;
high = null;
} else {
// set the indices to highlight
mIndicesToHighlight = new Highlight[]{
high
};
}
}
setLastHighlighted(mIndicesToHighlight);
if (callListener && mSelectionListener != null) {
if (!valuesToHighlight())
mSelectionListener.onNothingSelected();
else {
// notify the listener
mSelectionListener.onValueSelected(e, high);
}
}
// redraw the chart
invalidate();
}
前面一大段代码,就是检查这个Highlight有没有对应的Entry。如果没有,那就置Highlight = null.如果有,那就new 一个 Highlight数组。下面一段代码呢就是画出这个Highlight之后的一个触发监听,可以其中做些操作,不要太耗时。最重要的是有个方法,我们之前见过:
/**
* Returns true if there are values to highlight, false if there are no
* values to highlight. Checks if the highlight array is null, has a length
* of zero or if the first object is null.
* @return
*/
public boolean valuesToHighlight() {
return mIndicesToHighlight == null || mIndicesToHighlight.length <= 0
|| mIndicesToHighlight[0] == null ? false
: true;
}
在OnDraw方法中见到过,对吧,再回忆下:
if (valuesToHighlight())
mRenderer.drawHighlighted(canvas, mIndicesToHighlight);
满足这几个条件。才给你绘制Highlight。