重写MPAndroidChart显示标记
2024-08-31 14:29:12
MPAndroidChart是实现图表功能的优秀控件, 能够完毕大多数绘制需求. 对于改动第三方库而言, 优秀的架构是继承开发, 而不是把源代码拆分出去. MP在显示标记控件(MarkView)时, 会有异常, 导致标志在图表边缘显示不全, 则须要重写控件解决这个问题.
继承LineChart, 提取高亮位置坐标getHighLightPos
, 重绘标记drawMarkers
.
/**
* 数据中心的图表折线图, 继承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();
// 默认构造器
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);
}
// 获取高亮点坐标
public float[] getHighLightPos(Entry e, Highlight highlight) {
return getMarkerPosition(e, highlight);
}
// 重写这种方法, 修复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方法导出.
float tmpY = pos[1] - 8 * AppUtils.getPerDp();
, 又一次计算Y坐标, 偏离原始画布.
可是这样做有一个问题, 在移动MarkView时, 父控件会有残留. 怎样解决呢?
办法就是在移动时, 重绘父控件的canvas, 使用invalidate()
函数.
// 设置图表点击事件, 监听高亮位置
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() {
// 再次点击时调用这个, 要不非高亮
mLcChart.highlightValue(mIndex, 0);
}
});
// 外部设置图表高亮
private void setChartHighlight(int index) {
if (mLcChart.getData() == null) return;
mMarkerView.setDateText(mMarkers.get(index));
mLcChart.highlightValue(index, 0);
mLlContainer.invalidate(); // 重绘父控件, 避免残留
}
在图表控件中, 内部外部都会触发高亮位置.
OK, Enjoy It!
最新文章
- 安卓---Toast工具类,有点懒
- 【Spring3.0系列】---Bean不同配置方式比较 和适用场合
- 微信开发(03)之新建按钮时报错 errcode 40054
- 不会UML的程序员不是好构架师?
- Linux netmask
- PLSQL_基础系列09_时间戳记TIMESTAMP(案例)
- WebGoat学习——跨站脚本攻击(Cross‐Site Scripting (XSS))
- UVALive 5880 Vigen&#232;re Cipher Encryption (模拟)
- python(1) - 条件判断和循环
- SQLite学习第02天:数据类型
- Unty3D动态加载图片
- Missing iOS Distribution signing identity问题解决
- big_table练习数据表
- YII学习笔记-登录后的session的总结
- Java面试题之三
- .Net开源oss项目进度更新(含小程序接口)
- 【模板】埃拉托色尼筛法 &;&; 欧拉筛法 &;&; 积性函数
- java基础49 IO流技术(对象输入流/对象输出流)
- 587. Erect the Fence(凸包算法)
- linux下close 掉socket 之后 阻塞的recv 不会立即返回
热门文章
- vue自定义一个过滤器
- Set&;Map区别Array
- OO第一单元总结__多项式求导问题
- ActiveMQ学习总结(4)——业界消息队列简介
- 高级函数-decode
- NYIST 1070 诡异的电梯【Ⅰ】
- C#-常用对象-思维导图
- ZOJ 3494 BCD Code (AC自己主动机 + 数位DP)
- error[No partition metadata for topic test-1 due to kafka.common.LeaderNotAvailableException]
- CSS文本简单设置