我正在使用 MarkerView 类在图表中显示标记视图。我创建的标记视图布局包含两个文本视图,一个在另一个下面。
我面临的问题是图表上最后一个点的标记视图一半在图表内,一半在图表外。下面两张图清楚地说明了问题:
第一张图片显示了图表中心点的标记视图,显示没有任何问题:
第二张图片如下所示,显示了图表最后一个点的标记视图,该点位于图表内。
如何调整此标记视图以使其显示在图表区域内。
wiki 没有说明标记视图的任何自定义。还有更多定制吗?
此外,在多折线图的情况下,如果我仅单击其中一个线点,则标记视图不会出现问题。但是,如果我单击另一行上任何点的标记视图,应用程序就会失败。知道为什么会发生这种情况吗?
markerview 类的代码如下:
public class TooltipView extends MarkerView {
private BaseGraphMetadata mBaseGraphMetadata;
private TextView mTooltipDate, mTooltipValue;
public TooltipView(Context context, int layoutResource, BaseGraphMetadata baseGraphMetadata) {
super(context, layoutResource);
mTooltipDate = (TextView)findViewById(R.id.tooltip_date);
mTooltipValue = (TextView)findViewById(R.id.tooltip_value);
mBaseGraphMetadata = baseGraphMetadata;
}
@Override
public void refreshContent(Entry entry, int i) {
List<DrillDownInfo> drillDownInfoList = (List<DrillDownInfo>) entry.getData();
DrillDownInfo drillDownInfo = drillDownInfoList.get(i);
Map<String, String> group = drillDownInfo.getGroupByNameVsGroupByValue();
Iterator iterator = group.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pair = (Map.Entry)iterator.next();
if(pair.getKey()!=null && pair.getValue()!=null) {
String key = (String) pair.getKey();
key = key.toUpperCase();
Double value = Double.parseDouble((String) pair.getValue());
String formattedValue = mBaseGraphMetadata.getDataFormatter().getFormattedValue(value);
mTooltipDate.setText(key + " : " + formattedValue);
}
iterator.remove();
}
mTooltipValue.setText(String.valueOf("VALUE : "+entry.getVal()));
}
@Override
public int getXOffset() {
return -(getWidth() / 2);
}
@Override
public int getYOffset() {
return -getHeight();
}
}
我找到了解决这个问题的简单方法。您需要在自定义标记视图中设置图表,如下所示:
setChartView(chart);
..并重写绘制方法,如下所示:
@Override
public void draw(Canvas canvas, float posX, float posY) {
super.draw(canvas, posX, posY);
getOffsetForDrawingAtPoint(posX, posY);
}
自从
android:clipChildren="false"
android:clipToPadding="false"
对我来说不起作用,我最终创建了 3 个不同的可绘制对象。根据条目索引,我使用其中之一。并且,为了保持箭头居中,XOffset 会相应更改。我想这是一个非常具体的解决方案,但这个想法是可以导出的
@Override
public void refreshContent(Entry e, int dataSetIndex) {
if (e.getXIndex() < 4) {
xOffsetMultiplier = 3.2f;
tvContent.setBackgroundResource(R.drawable.stats_marker_left_side);
} else if (e.getXIndex() > mTimestamps.length - 6) {
//timestamps is an array containing xValues timestamps
xOffsetMultiplier = 1.12f;
tvContent.setBackgroundResource(R.drawable.stats_marker_right_side);
} else {
xOffsetMultiplier = 2;
tvContent.setBackgroundResource(R.drawable.stats_marker);
}
tvContent.setText(createMarkerViewText(e));
}
@Override
public int getXOffset() {
// this will center the marker-view horizontally
return (int) -(getWidth() / xOffsetMultiplier);
}
这就是结果
可绘制对象是从 MPAndroidChart 示例复制的,转换为 9.patch 并适应我的需求。将它们放在drawable-nodpi内
有点晚了,但这是我解决这个问题的简单方法。
您需要
Override
自定义draw
的MarkerView
方法。
然后您只需控制 posx 不会从您的边框之一关闭(从右侧的
0
到取决于您的屏幕尺寸的位置,例如我自己的屏幕的 300
)。
一个简单的例子:
@Override
public void draw(Canvas canvas, float posx, float posy)
{
// take offsets into consideration
posx += getXOffset();
posy=0;
// AVOID OFFSCREEN
if(posx<45)
posx=45;
if(posx>265)
posx=265;
// translate to the correct position and draw
canvas.translate(posx, posy);
draw(canvas);
canvas.translate(-posx, -posy);
}
在这里,我可以控制我的 x 位置,同时确保标记始终位于图表的顶部(如果您不想要它,请使用 p
osy += getYOffset();
代替)
只需在您的
MarkerView
中添加一些逻辑即可。如果突出显示最后一个值,则 getXOffset()
方法应返回不同的内容。
返回的内容是在
refreshContent(...)
方法中计算的。
此外,您还可以查看以下 xml 属性:
android:clipChildren="false"
android:clipToPadding="false"
应该为图表视图设置。
试试这个:
private val uiScreenWidth = resources.displayMetrics.widthPixels
override fun draw(canvas: Canvas?, posX: Float, posY: Float) {
var newPosX = posX
if (uiScreenWidth - posX < width) {
newPosX -= width
}
super.draw(canvas, newPosX, posY)
}
我也遇到了同样的问题。我通过制作自己的
customMarkerview
类来纠正它,特别是下面的方法:
@Override
public int getXOffset(float xpos) {
// this will center the marker-view horizontally
int min_offset = 50;
if (xpos < min_offset)
return 0;
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
//For right hand side
if (metrics.widthPixels - xpos < min_offset)
return -getWidth();
//For left hand side
else if (metrics.widthPixels - xpos < 0)
return -getWidth();
return -(getWidth() / 2);
}
您可以通过添加
chart.setDragOffsetX(50);
来纠正此问题。这将在 x 轴上添加填充。因此,为要显示的标记视图提供了空间。
最好的答案就在图书馆本身。检查 MarkerView 中的 getOffsetForDrawingAtPoint() 方法。它定义了计算偏移的完美方法。从那里使用该逻辑并在自定义标记的
onDraw
方法中使用,如下所示:
@Override
public void draw(Canvas canvas, float posX, float posY) {
// take offsets into consideration
int lineChartWidth = 0;
float offsetX = getOffset().getX();
posY=0;//fix at top
float width = getWidth();
if(lineChart != null) {
lineChartWidth = lineChart.getWidth();
}
if(posX + offsetX < 0) {
offsetX = - posX;
} else if(posX + width + offsetX > lineChartWidth) {
offsetX = lineChartWidth - posX - width;
}
posX += offsetX;
// translate to the correct position and draw
canvas.translate(posX, posY);
draw(canvas);
canvas.translate(-posX, -posY);
}
就我而言是: 首先,您只需在 customMarkerView 类中重写 getOffset() 并返回 MPPointF(-(width / 2f), -height.toFloat())
之后,将图表视图设置为MarkerView.chartView。
就我而言是这样的。
val 标记=CustomMarkerView(requireContext(),R.layout.custom_market_view,dataMarker) 标记.chartView = 绑定.chartDiscover