效果
本文的合集已經(jīng)編著成書,高級Android開發(fā)強(qiáng)化實戰(zhàn),歡迎各位讀友的建議和指導(dǎo)。在京東即可購買:https://item.jd.com/12385680.html
Android
MPAndroidChart是實現(xiàn)圖表功能的優(yōu)秀控件, 可以完成大多數(shù)繪制需求. 對于修改第三方庫而言, 優(yōu)秀的架構(gòu)是繼承開發(fā), 而不是把源碼拆分出去. MP在顯示標(biāo)記控件(MarkView)時, 會有異常, 導(dǎo)致標(biāo)志在圖表邊緣顯示不全, 則需要重寫控件解決問題.
繼承LineChart, 提取高亮位置坐標(biāo)getHighLightPos
, 重繪標(biāo)記drawMarkers
.
/**
* 數(shù)據(jù)中心的圖表折線圖, 繼承MPChart的折線圖
* <p>
* Created by wangchenlong on 15/10/13.
*/
public class CYDataLineChart extends LineChart {
@SuppressWarnings("unused")
private static final String TAG = "DEBUG-WCL: " + CYDataLineChart.class.getSimpleName();
// 默認(rèn)構(gòu)造器
public CYDataLineChart(Context context) {
super(context);
}
public CYDataLineChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CYDataLineChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// 獲取高亮點坐標(biāo)
public float[] getHighLightPos(Entry e, Highlight highlight) {
return getMarkerPosition(e, highlight);
}
// 重寫這個方法, 修復(fù)Bug
@Override
protected void drawMarkers(Canvas canvas) {
// if there is no marker view or drawing marker is disabled
if (mMarkerView == null || !mDrawMarkerViews || !valuesToHighlight())
return;
Rect newRect = canvas.getClipBounds();
newRect.inset(-80, 0); //make the rect larger
canvas.clipRect(newRect, Region.Op.REPLACE);
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < mIndicesToHighlight.length; i++) {
Highlight highlight = mIndicesToHighlight[i];
int xIndex = highlight.getXIndex();
if (xIndex <= mDeltaX && xIndex <= mDeltaX * mAnimator.getPhaseX()) {
Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
// make sure entry not null
if (e == null || e.getXIndex() != mIndicesToHighlight[i].getXIndex())
continue;
float[] pos = getMarkerPosition(e, highlight);
// Marker偏移
float tmpY = pos[1] - 8 * AppUtils.getPerDp();
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
// noinspection deprecation
paint.setColor(getResources().getColor(R.color.chart_circle));
canvas.drawCircle(pos[0], pos[1], 2 * AppUtils.getPerDp(), paint);
// check bounds
if (!mViewPortHandler.isInBounds(pos[0], tmpY))
continue;
mMarkerView.refreshContent(e, highlight);
mMarkerView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
mMarkerView.layout(0, 0, mMarkerView.getMeasuredWidth(),
mMarkerView.getMeasuredHeight());
if (tmpY - mMarkerView.getHeight() <= 0) {
float y = mMarkerView.getHeight() - tmpY;
mMarkerView.draw(canvas, pos[0], tmpY + y);
} else {
mMarkerView.draw(canvas, pos[0], tmpY);
}
}
}
}
}
getMarkerPosition
是LineChart類中的protected方法, 繼承類, 使用public方法導(dǎo)出.
float tmpY = pos[1] - 8 * AppUtils.getPerDp();
, 重新計算Y坐標(biāo), 偏離原始畫布.
但是這樣做有一個問題, 在移動MarkView時, 父控件會有殘留. 如何解決呢? 辦法就是在移動時, 重繪父控件的canvas, 使用invalidate()
函數(shù).
// 設(shè)置圖表點擊事件, 監(jiān)聽高亮位置
mLcChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, int dataSetIndex, Highlight h) {
int index = e.getXIndex();
Log.e(TAG, "index = " + index);
setChartIndex(index);
mCallback.setCurIndex(index);
mIndex = index;
float[] pos = mLcChart.getHighLightPos(e, h);
Log.e(TAG, "x: " + pos[0] + ", y: " + pos[1]);
mLlContainer.invalidate(); // 重繪父控件, 避免殘留
}
@Override
public void onNothingSelected() {
// 再次點擊時調(diào)用這個, 要不非高亮
mLcChart.highlightValue(mIndex, 0);
}
});
// 外部設(shè)置圖表高亮
private void setChartHighlight(int index) {
if (mLcChart.getData() == null) return;
mMarkerView.setDateText(mMarkers.get(index));
mLcChart.highlightValue(index, 0);
mLlContainer.invalidate(); // 重繪父控件, 避免殘留
}
在圖表控件中, 內(nèi)部外部都會觸發(fā)高亮位置.
動畫
OK, Enjoy It!