【问题标题】:MarkerView goes out of the chart for the last point on the chartMarkerView 在图表上的最后一个点走出图表
【发布时间】:2015-07-22 01:19:36
【问题描述】:

我正在使用 MarkerView 类在图表中显示标记视图。我创建的标记视图布局包含两个文本视图,一个在另一个之下。

我面临的问题是图表上最后一个点的标记视图一半在图表内,一半在图表外。下面的两张图片清楚地说明了问题:

第一张图片显示了图表中心点的标记视图,显示没有任何问题:

如下图所示,第二张图片显示了图表最后一个点的标记视图,该点位于图表内的一半。

如何调整此标记视图以使其显示在图表区域内。

wiki 没有声明标记视图的任何自定义。还有更多的自定义吗?

另外,在多折线图的情况下,如果我只点击其中一个折线点,markerview 就没有问题。但是,如果我在另一行的任何一点上单击标记视图,应用程序就会失败。知道为什么会这样。

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();
}
}

【问题讨论】:

    标签: android charts mpandroidchart


    【解决方案1】:

    我找到了解决这个问题的简单方法。您需要在自定义标记视图中设置图表,如下所示:

    setChartView(chart);
    

    ..并重写draw方法如下:

    @Override
    public void draw(Canvas canvas, float posX, float posY) {
        super.draw(canvas, posX, posY);
        getOffsetForDrawingAtPoint(posX, posY);
    }
    

    【讨论】:

      【解决方案2】:

      自从

      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);
        }
      

      这是结果

      drawables 从 MPAndroidChart 示例中复制,转换为 9.patch 并适应我的需要。将它们放在 drawable-nodpi 中

      【讨论】:

      • 有工具可以创建 9 个补丁图像。但是它们是如何运作的呢?另外我如何将普通图像转换为 9 补丁?
      【解决方案3】:

      有点晚了,但这是我解决这个问题的简单方法。

      您需要Override 自定义MarkerViewdraw 方法。

      然后您只需控制您的 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 位置,同时确保标记始终位于图表顶部(如果您不想要它,请改用 posy += getYOffset();

      【讨论】:

        【解决方案4】:

        只需在您的MarkerView 中添加一些逻辑即可。如果最后一个值被突出显示,getXOffset() 方法应该返回不同的值。

        返回的内容在refreshContent(...) 方法中计算。

        此外,您可以查看以下 xml 属性:

        android:clipChildren="false"
        android:clipToPadding="false"
        

        应该为图表视图设置。

        【讨论】:

        • 这两个 XML 属性没有帮助。
        • 另外,当我点击图表上的一个点时,我会看到两条线在点击的点处相交。请参考问题中的图片。如何删除这些行?
        • 它们被称为高亮指示线,看看the documentation
        • 由于 getXOffset() 已被弃用,此答案不再有效
        【解决方案5】:

        我遇到了同样的问题。我通过制作自己的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);
        }
        

        【讨论】:

          【解决方案6】:

          试试这个:

              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)
              }
          

          【讨论】:

          • 这应该是新接受的答案
          【解决方案7】:

          最好的答案在于图书馆本身。检查来自 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);
              }
          

          【讨论】:

          • 你不需要覆盖draw,如果你调用setChartView(chart)那么getOffsetForDrawingAtPoint()会正确计算偏移量
          【解决方案8】:

          您可以通过添加 chart.setDragOffsetX(50); 来纠正此问题。这将在 x 轴上添加填充。因此,为要显示的标记视图留出空间。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-01-24
            • 2021-08-20
            • 1970-01-01
            相关资源
            最近更新 更多