修改前:
修改后:
image.png
MPAndroidChart https://github.com/PhilJay/MPAndroidChart
通过自定义markview来实现,重新里面重要的两个方法getOffset draw
通过draw拿到markView的宽度()、markView的高度()、折线图的宽度()、折线图的高度()来设置Point的偏移量
activity
import android.graphics.Color
import android.os.Bundle
import android.view.Window
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import com.alibaba.fastjson.JSON
import kotlinx.android.synthetic.main.activity_line_chart.*
/**
*@Description: 折线图
*/
class LineChartActivity : AppCompatActivity() {
var entries = arrayListOf<Entry>()
var entriestwo = arrayListOf<Entry>()
var week = arrayListOf<String>()
var dataSet:LineDataSet? = null
var dataSettwo:LineDataSet? = null
var jsonStr = "[\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-01-20 15:36:46\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-01-20 15:36:46\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 01:59:57\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 01:59:58\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 01:59:59\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 01:59:59\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 01:59:59\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:00:50\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:01:00\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:01:05\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:01:08\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:09\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:10\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:10\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:10\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:11\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:11\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"130\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:05:11\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"80\",\n" +
" \"dia\":\"120\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 02:06:43\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"126\",\n" +
" \"dia\":\"89\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 14:34:46\"\n" +
" },\n" +
" {\n" +
" \"testOrg\":\"智小马血压设备\",\n" +
" \"optionData\":{\n" +
" \"unit\":\"mmHg\",\n" +
" \"sys\":\"121\",\n" +
" \"dia\":\"82\"\n" +
" },\n" +
" \"cgyName\":\"血压\",\n" +
" \"diagnoseTime\":\"2021-07-15 14:38:56\"\n" +
" },\n" +
"]"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE)//去掉标题栏
setContentView(R.layout.activity_line_chart)
//设置数据
initData()
val description = chart?.getDescription()
description?.setText("历史数据折线图"); // 设置右下角备注
//设置颜色 及 标题
dataSet = LineDataSet(entries, "收缩压") // 图表绑定数据,设置图表折现备注
dataSet?.setColor(Color.parseColor("#5B8FF9")) // 设置折线图颜色
dataSet?.setValueTextColor(Color.parseColor("#5B8FF9")) // 设置数据值的颜色
// dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);// 设置平滑曲线
dataSet?.setValueTextSize(12f);//设置折线图转择点的值的大小
dataSet?.setDrawCircles(false) //设置是否绘制圆形指示器,默认true
dataSet?.setDrawValues(false);//在点上显示数值 默认true
dataSet?.setHighLightColor(Color.parseColor("#ABB5EA")) //折线图高亮坐标线的颜色
//设置颜色 及 标题
dataSettwo = LineDataSet(entriestwo, "舒张压"); // 图表绑定数据,设置图表折现备注
dataSettwo?.setColor(Color.parseColor("#5AD8A6")); // 设置折线图颜色
dataSettwo?.setValueTextColor(Color.parseColor("#5B8FF9")); // 设置数据值的颜色
// dataSettwo.setMode(LineDataSet.Mode.CUBIC_BEZIER);// 设置平滑曲线
dataSettwo?.setValueTextSize(12f);//设置折线图转择点的值的大小
dataSettwo?.setDrawCircles(false)//设置是否绘制圆形指示器,默认true
dataSettwo?.setDrawValues(false);//在点上显示数值 默认true
dataSettwo?.setHighLightColor(Color.parseColor("#ABB5EA")) //折线图高亮坐标线的颜色
//装载数据 todo
val lineData = LineData(dataSet,dataSettwo)
// val lineData = LineData(dataSet)
chart.data = lineData // 图表绑定数据值
// chart.animateXY(2000,1000)
chart.animateX(2000)
chart.invalidate() // 刷新图表
}
private fun initData() {
val list = JSON.parseArray(jsonStr.toString(),ChartBean::class.java)
list.forEachIndexed { index, chartBean ->
week.add(chartBean.diagnoseTime.split(" ")[0])
entries.add(Entry(index.toFloat(), chartBean.optionData.sys))
entriestwo.add(Entry(index.toFloat(), chartBean.optionData.dia))
}
chart.setNoDataText("暂无数据")
// 不可以缩放
chart.setScaleEnabled(false);
chart.setPinchZoom(false);
// chart?.setMaxVisibleValueCount(60); //最大显示的个数。超过60个将不再显示
//设置一页最大显示个数为6,超出部分就滑动
// val ratio = entries.size / 18;
chart.zoom(2.5f,1f,0f,0f);//显示的时候 是 按照多大的比率缩放显示 1f表示不放大缩小
//是否展示网格线
chart.setDrawGridBackground(false)
val valueFormatter: ValueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
val index = value.toInt()
return if (index >= 0 && index < week.size) week[index] else ""
}
}
//设置markerview todo
chart.marker = XYMarkerView(this,chart,valueFormatter,entries,entriestwo)
// chart.marker = XYMarkerSingleView(this,chart,valueFormatter,entries)
chart.setScaleMinima(1f,1f)
/***折线图例 标签 设置***/
val legend = chart.getLegend();
legend.setForm(Legend.LegendForm.LINE);
legend.setTextSize(11f);
legend.setTextColor(Color.WHITE);
//显示位置
legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
legend.setXEntrySpace(15f);
legend.setYEntrySpace(15f);
//是否绘制在图表里面
legend.setDrawInside(false);
//x轴设置
val xAxis = chart.getXAxis()
// 不显示x轴
xAxis.setDrawAxisLine(true)
// 设置x轴数据的位置
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.textColor = Color.WHITE
xAxis.textSize = 6f
xAxis.gridColor = Color.parseColor("#3E466D")
// xAxis.setAxisMinimum(0f);
xAxis.setGranularity(1f);//设置Y轴最小间隔
xAxis.axisLineColor = Color.parseColor("#3E466D")
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); // 让x轴在下面
xAxis.setGridColor(getResources().getColor(android.R.color.transparent));
xAxis.setAvoidFirstLastClipping(true)//是否避免图表或屏幕的边缘的第一个和最后一个轴中的标签条目被裁剪
// xAxis.setLabelRotationAngle(-30f); //对X轴进行一定角度的旋转,看着有立体效果,还能减小字体重叠
xAxis.valueFormatter = valueFormatter
//y轴设置
val leftYAxis = chart.getAxisLeft();
val rightYaxis = chart.getAxisRight();
//保证Y轴从0开始,不然会上移一点
leftYAxis.textColor = Color.WHITE
leftYAxis.setDrawLabels(true)
leftYAxis.axisMinimum = 0f
leftYAxis.axisMaximum = 200f
leftYAxis.axisLineColor = getResources().getColor(android.R.color.transparent)
leftYAxis.setLabelCount(6, true)
// leftYAxis.setEnabled(false); // 隐藏左边 的坐标轴
rightYaxis.setEnabled(false); // 隐藏右边 的坐标轴
}
}
自定义markview
package com.dsy.tui.line;
import android.content.Context;
import android.graphics.Canvas;
import android.widget.TextView;
import com.dsy.tui.R;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;
import java.text.DecimalFormat;
import java.util.List;
public class XYMarkerView extends MarkerView {
private TextView tvTime;
private TextView tvChart;
private TextView tvChartTwo;
private DecimalFormat format;
private List<Entry> entries;
private List<Entry> entriesTwo;
private LineChart chart;
private IAxisValueFormatter xAxisValueFormatter;
private Context context;
public XYMarkerView(Context context, LineChart chart, IAxisValueFormatter xAxisValueFormatter, List<Entry> entries, List<Entry> entriesTwo) {
super(context, R.layout.custom_marker_view);
this.context = context;
tvTime = (TextView) findViewById(R.id.tvTime);
tvChart = (TextView) findViewById(R.id.tvChart);
tvChartTwo = (TextView) findViewById(R.id.tvChartTwo);
format = new DecimalFormat("###.0");
this.entries = entries;
this.xAxisValueFormatter = xAxisValueFormatter;
this.entriesTwo = entriesTwo;
this.chart = chart;
}
//回调函数每次MarkerView重绘,可以用来更新内容(用户界面)
@Override
public void refreshContent(Entry e, Highlight highlight) {
LineData lineData = chart.getLineData();//得到已经绘制成型的折线图的数据
LineDataSet set = (LineDataSet)lineData.getDataSetByIndex(0);//获取第一条折线图Y轴数据
LineDataSet set2 = (LineDataSet)lineData.getDataSetByIndex(1);//获取第二条折线图Y轴数据
int DataSetIndex = highlight.getDataSetIndex();//获取点击的是哪条折线上的交叉点,0就是第一条,以此类推
int index;
if (DataSetIndex == 0){
index = set.getEntryIndex(e);//根据点击的该条折线的点,获取当前Y轴数据对应的index值
}else {
index = set2.getEntryIndex(e);//根据点击的该条折线的点,获取当前Y轴数据对应的index值
}
//根据index值,分别获取当前X轴上对应的两条折线的Y轴的值
Entry entry = set.getEntryForIndex(index);
Entry entry2 = set2.getEntryForIndex(index);
tvTime.setText(xAxisValueFormatter.getFormattedValue(e.getX(), null));
tvChart.setText("" + entry.getY());
tvChartTwo.setText("" + entry2.getY());
super.refreshContent(e, highlight);
}
//设置显示偏移位置
@Override
public MPPointF getOffset() {
return new MPPointF((getWidth() / 8), -getHeight());
}
//这里修改markview偏移
public void draw(Canvas canvas, float posX, float posY) {
MPPointF mpPointF = new MPPointF();
//根据项目需求通过width、height、chartWidth、chartHeight来设置point偏移位置
float width = getWidth();//markview宽度
float height = getHeight();//markview的高度
float chartWidth = chart.getWidth();//chart宽度
float chartHeight = chart.getHeight();//chart的高度
//右边超出的情况,显示一个,隐藏一个,设置对应的偏移量
if (chartWidth < posX + width) {
mpPointF.x = - (dip2px(context,10f) + getWidth());
} else {//右边没有超出的情况,同上
mpPointF.x = dip2px(context,10f);
}
//绘制方法是直接复制过来的,没动
int saveId = canvas.save();
// translate to the correct position and draw
canvas.translate(posX + mpPointF.x, posY + mpPointF.y);
draw(canvas);
canvas.restoreToCount(saveId);
}
public int dip2px(Context context, float dipValue){
final float scale = context.getResources().getDisplayMetrics().density;
return (int)(dipValue * scale + 0.5f);
}
}
自定义markview的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:orientation="vertical"
android:padding="@dimen/p10"
android:layout_height="wrap_content"
android:background="#3D405E">
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="2020.12.24"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white"
android:textSize="12dp"/>
<LinearLayout
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:background="#5B8FF9"
android:layout_width="@dimen/p10"
android:layout_height="2dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="收缩压"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white"
android:textSize="12dp"/>
<TextView
android:id="@+id/tvChart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="35dp"
android:text="0.00"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white"
android:textSize="12dp"/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:background="#5AD8A6"
android:layout_width="@dimen/p10"
android:layout_height="2dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="舒张压"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white"
android:textSize="12dp"/>
<TextView
android:id="@+id/tvChartTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="35dp"
android:text="0.00"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white"
android:textSize="12dp"/>
</LinearLayout>
</LinearLayout>
主布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_rect_gradient_262949_to_100f19"
android:orientation="vertical">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
设置均值线
image.png设置代码如下
//均值线
val avgLine = LimitLine(100f)
avgLine.enableDashedLine(5.0f, 3.0f, 3.0f)
avgLine.lineColor = Color.parseColor("#33CC33")
leftYAxis.addLimitLine(avgLine)
网友评论