前言:
过了一个愉快的五一后,我们又开始上班了,完成了本分的工作,抽点时间来和说说MarkerView咯。给我的印象,MarkerView的扩展性很强。它可以自定义自己想要的U样式.
MarkerView源码
/**
* View that can be displayed when selecting values in the chart. Extend this class to provide custom layouts for your
* markers.
*
* @author Philipp Jahoda
*/
public class MarkerView extends RelativeLayout implements IMarker {
private MPPointF mOffset = new MPPointF();
private MPPointF mOffset2 = new MPPointF();
private WeakReference<Chart> mWeakChart;
/**
* Constructor. Sets up the MarkerView with a custom layout resource.
*
* @param context
* @param layoutResource the layout resource to use for the MarkerView
*/
public MarkerView(Context context, int layoutResource) {
super(context);
setupLayoutResource(layoutResource);
}
/**
* Sets the layout resource for a custom MarkerView.
*
* @param layoutResource
*/
private void setupLayoutResource(int layoutResource) {
View inflated = LayoutInflater.from(getContext()).inflate(layoutResource, this);
inflated.setLayoutParams(new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
inflated.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
// measure(getWidth(), getHeight());
inflated.layout(0, 0, inflated.getMeasuredWidth(), inflated.getMeasuredHeight());
}
public void setOffset(MPPointF offset) {
mOffset = offset;
if (mOffset == null) {
mOffset = new MPPointF();
}
}
public void setOffset(float offsetX, float offsetY) {
mOffset.x = offsetX;
mOffset.y = offsetY;
}
@Override
public MPPointF getOffset() {
return mOffset;
}
public void setChartView(Chart chart) {
mWeakChart = new WeakReference<>(chart);
}
public Chart getChartView() {
return mWeakChart == null ? null : mWeakChart.get();
}
@Override
public MPPointF getOffsetForDrawingAtPoint(float posX, float posY) {
MPPointF offset = getOffset();
mOffset2.x = offset.x;
mOffset2.y = offset.y;
Chart chart = getChartView();
float width = getWidth();
float height = getHeight();
if (posX + mOffset2.x < 0) {
mOffset2.x = - posX;
} else if (chart != null && posX + width + mOffset2.x > chart.getWidth()) {
mOffset2.x = chart.getWidth() - posX - width;
}
if (posY + mOffset2.y < 0) {
mOffset2.y = - posY;
} else if (chart != null && posY + height + mOffset2.y > chart.getHeight()) {
mOffset2.y = chart.getHeight() - posY - height;
}
return mOffset2;
}
@Override
public void refreshContent(Entry e, Highlight highlight) {
measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
@Override
public void draw(Canvas canvas, float posX, float posY) {
MPPointF offset = getOffsetForDrawingAtPoint(posX, posY);
int saveId = canvas.save();
// translate to the correct position and draw
canvas.translate(posX + offset.x, posY + offset.y);
draw(canvas);
canvas.restoreToCount(saveId);
}
}
MarkerView继承了RelativeLayout,所以说它相当于一个View容器,你只管往里面放View就好了。至于啥样子,就不管了,由你来掌控。它还实现了IMarker接口,IMarker接口中的方法有如下几个:
MPPointF getOffset();
MPPointF getOffsetForDrawingAtPoint(float posX, float posY);
void refreshContent(Entry e, Highlight highlight);
void draw(Canvas canvas, float posX, float posY);
draw方法,就是去画你自定义的MarkerView的内容,posX,posY,就是画在指定的点。
refreshContent方法,顾名思义,就是刷新MarkerView的内容。传了两个参数,一个是Entry,一个是Highlight,可以知道,这个与Highlight有密切的关系。也就是说,只有在选择了一个Entry高亮显示了,才会画出这个刷新画出MarkerView。
getOffsetForDrawingAtPoint方法,与画的点的位置有关系,一个偏移量
getOffset方法,就是偏移量咯。
实际使用
在MarkerView中还有一个方法被我们忽视了,setupLayoutResource(int layoutResource)。这个方法就是加载你自定义的xml文件。我们来看下demo中自定义的MarkerView。
public class MyMarkerView extends MarkerView {
private TextView tvContent;
public MyMarkerView(Context context, int layoutResource) {
super(context, layoutResource);
tvContent = (TextView) findViewById(R.id.tvContent);
}
// callbacks everytime the MarkerView is redrawn, can be used to update the
// content (user-interface)
@Override
public void refreshContent(Entry e, Highlight highlight) {
if (e instanceof CandleEntry) {
CandleEntry ce = (CandleEntry) e;
tvContent.setText("" + Utils.formatNumber(ce.getHigh(), 0, true));
} else {
tvContent.setText("" + Utils.formatNumber(e.getY(), 0, true));
}
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
}
重写了refreshContent方法 , getOffset()方法。如何使用的呢?
MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view);
mv.setChartView(mChart); // For bounds control
mChart.setMarker(mv); // Set the marker to the chart
先new 一个MyMarkerView,然后设置到Chart中去。在绘制的时候就可以绘制你自定义的xml了。在Chart中有一个drawMarkers方法:
protected void drawMarkers(Canvas canvas) {
// if there is no marker view or drawing marker is disabled
if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
return;
for (int i = 0; i < mIndicesToHighlight.length; i++) {
Highlight highlight = mIndicesToHighlight[i];
IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex());
Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
int entryIndex = set.getEntryIndex(e);
// make sure entry not null
if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
continue;
float[] pos = getMarkerPosition(highlight);
// check bounds
if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
continue;
// callbacks to update the content
mMarker.refreshContent(e, highlight);
// draw the marker
mMarker.draw(canvas, pos[0], pos[1]);
}
}
最主要的就是最后两行代码,先刷新UI,再去画。以上就是对MarkerView的介绍了。下次再会!