1. 程式人生 > >MPAndroidChart 教程:MarkerView(十一)

MPAndroidChart 教程:MarkerView(十一)

一、什麼是MarkerView

首先來看 MarkerView 的效果圖:

如上圖所示,當點選折線圖上的點時,會彈出一個View,這就是 Markerview

  • 上面的左圖是一個 TextView 佈局和一個橢圓黑色的 background
  • 右圖是一個 TextView 佈局和一個 bitmapbackground

那麼這具體是如何實現的呢?

二、MakerView 抽象類

1. 簡介

為顯示自定義的(彈出的)擴充套件View並且使得點選的點的值在圖表中突出顯示,我們可以建立一個類並繼承MakerView 抽象類,然後實現該類的構造方法和繼承自 MarkerView

類的抽象方法 。

    // extend MarkerView
    public class YourCustomMarkerView extends MarkerView { ...
  • MarkerView 類繼承自 RelativeLayout

2. MarkerView 類原始碼:

/**
 * View that can be displayed when selecting values in the chart. 
 * Extend this class to provide custom layouts for your markers.
 */
public
abstract class MarkerView extends RelativeLayout { /** * 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()); } /** * Draws the MarkerView on the given position on the screen * with the given Canvas object. * * @param canvas * @param posx * @param posy */ public void draw(Canvas canvas, float posx, float posy) { // take offsets into consideration posx += getXOffset(posx); posy += getYOffset(posy); // translate to the correct position and draw canvas.translate(posx, posy); draw(canvas); canvas.translate(-posx, -posy); } /** * This method enables a specified custom MarkerView to * update it's content everytime the MarkerView is redrawn. * * @param e The Entry the MarkerView belongs to. This can * also be any subclass of Entry, like BarEntry or CandleEntry, * simply cast it at runtime. * @param highlight The highlight object contains information * about the highlighted value such as it's dataset-index, the * selected range or stack-index (only stacked bar entries). */ public abstract void refreshContent(Entry e, Highlight highlight); /** * Use this to return the desired offset you wish the MarkerView * to have on the x-axis. By returning -(getWidth() / * 2) you will center the MarkerView horizontally. * * @param xpos the position on the x-axis in pixels where the marker is drawn * @return */ public abstract int getXOffset(float xpos); /** * Use this to return the desired position offset you wish the MarkerView * to have on the y-axis. By returning * -getHeight() you will cause the MarkerView to be above the selected value. * * @param ypos the position on the y-axis in pixels where the marker is drawn * @return */ public abstract int getYOffset(float ypos); }

3. 設定/獲取 MarkerView 的方法

  • setMarkerView(MarkerView mv) : 為 chart 設定一個 MarkerView 從而顯示選中的值。
  • getMarkerView() : 獲取 chart 已經設定了的 MarkerView ,未設定的話返回 null

三、實現步驟

後面你可以找到一個實現自定義 MarkerView 類的例子。 重要的是,在這個過程中要實現以下從 MarkerView 抽象類繼承來的方法:

  • refreshContent(Entry e, Highlight highlight) : 每次 MarkerView 重繪此方法都會被呼叫,併為您提供更新它顯示的內容的機會(例如,為一個 TextView 設定文字 ,…)。 它提供了當前突出顯示的 Entry 和相應的Highlight物件以獲得更多資訊。
  • getXOffset(float xpos) : 在這裡,應返回要繪製的 MarkerView 在x軸的偏移位置。 預設情況下,MarkerView 的左上邊緣處將繪製在 entry 的位置。 在 xpos 引數表示繪製 MarkerView 的預設位置。
  • getYOffset(float ypos) : 在這裡,應返回要繪製的 MarkerView 在y軸的偏移位置。 預設情況下,MarkerView 的左上邊緣處將繪製在 entry 的位置。 在 ypos 引數表示繪製MarkerView 的預設位置。

實現自定義 MarkerView 類的例子:

public class CustomMarkerView extends MarkerView {

    private TextView tvContent;

    public CustomMarkerView (Context context, int layoutResource) {
        super(context, layoutResource);
        // this markerview only displays a textview
        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) {
        tvContent.setText("" + e.getVal()); // set the entry-value as the display text
    }

    @Override
    public int getXOffset(float xpos) {
        // this will center the marker-view horizontally
        return -(getWidth() / 2);
    }

    @Override
    public int getYOffset(float ypos) {
        // this will cause the marker-view to be above the selected value
        return -getHeight();
    }
}
  • 實現自定義的 MarkerView 類後,需要建立一個 .xml 檔案來作為 MarkerView 的佈局。 本例項的佈局僅是一個有背景圖的且內含一個TextViewRelativeLayout ,但 你可以建立任何你想要在這裡顯示的佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:background="@drawable/markerImage" >

    <TextView
        android:id="@+id/tvContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text=""
        android:textSize="12dp"
        android:textColor="@android:color/white"
        android:ellipsize="end"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceSmall" />

</RelativeLayout>
  • 最後,為圖表設定你已經建立了的自定義 MarkerView。 建立 MarkerView 時請確保你建立的 .xml 檔案提供了對應的 layout 資源。
    CustomMarkerView mv = new CustomMarkerView(Context, 
        R.layout.custom_marker_view_layout);

    // set the marker to the chart
    chart.setMarkerView(mv);

四、 隨手寫的一個樣例

1. 動態效果圖

2. 主要程式碼

1) 背景圖 bg_marker.xml

<!-- bg_marker.xml -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <solid android:color="@android:color/black"/>
</shape>

2) 佈局程式碼 content_marker_view.xml

<!-- content_marker_view.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="72dp"
                android:layout_height="48dp"
                android:background="@drawable/bg_marker"
                android:gravity="center"
                android:orientation="vertical">

    <TextView
        android:id="@+id/tv_content_marker_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="4dp"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="@android:color/white"
        android:textSize="18sp"/>
</RelativeLayout>

3) 自定義的 MyMarkerView.java

public class MyMarkerView extends MarkerView {
    private TextView mContentTv;

    public MyMarkerView(Context context, int layoutResource) {
        super(context, layoutResource);
        mContentTv = (TextView) findViewById(R.id.tv_content_marker_view);
    }

    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        mContentTv.setText("" + e.getVal());
    }

    @Override
    public int getXOffset(float xpos) {
        return -(getWidth() / 2);
    }

    @Override
    public int getYOffset(float ypos) {
        return -getHeight();
    }
}

4) 為圖表設定 MarkerView

    // 設定MarkerView
    MarkerView mv = new MyMarkerView(this,R.layout.content_marker_view);
    chart.setMarkerView(mv);

本節完。