一 简介
1.1 图表用于直观的分析数据的分布情况,用于对比数据的大小和趋势。
1.2 图表的类型也非常多,常见的有折线,柱状,饼状,其它的有面积,散点,股价,雷达,仪表盘,漏斗等。
1.3 Android也有非常优秀的图表库,比如MPAndroidChart,hellocharts-android,AnyChart-Android等,其中MPAndroidChart目前使用量第一,优势在于自定义程度非常高,而且配置参数非常多,通过配置就能基本上实现所有的图表。
二 MPAndroidChart图表案例,柱状图
2.1 效果
2.2 添加 MPAndroidChart 依赖库
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}
2.4 xml添加柱状图组件BarChart
2.5 设置图表配置和数据
public class BarActivity extends AppCompatActivity {
private BarChart chart;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bar_chart);
//获取柱状图控件
chart = findViewById(R.id.chart1);
//初始化柱状图控件
initBarChart();
}
/**
* 初始化柱状图控件
*/
private void initBarChart(){
// 是否显示描述
chart.getDescription().setEnabled(false);
// 如果图表中显示的条目超过60个,则不会显示任何值
chart.setMaxVisibleValueCount(60);
// 只能分别在x轴和y轴上进行缩放
chart.setPinchZoom(false);
// 阴影
chart.setDrawBarShadow(false);
// 是否绘制背景线
chart.setDrawGridBackground(false);
// x坐标绘制
XAxis xAxis = chart.getXAxis();
// x坐标位置
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
// x坐标线
xAxis.setDrawGridLines(false);
//Y轴左边第1条线
chart.getAxisLeft().setDrawGridLines(false);
// 添加一个漂亮平滑的动画
chart.animateY(1500);
// 是否绘制图例
chart.getLegend().setEnabled(false);
//设置数据
setData();
}
/**
* 设置数据
*/
private void setData(){
//柱状数量 相当于二位数组的 二级数据
ArrayList values = new ArrayList<>();
for (int i = 0; i < 10; i++) {
float multi = (10 + 1);
float val = (float) (Math.random() * multi) + multi / 3;
values.add(new BarEntry(i, val));
}
// 柱状分类,相当于二位数组的 一级数据
BarDataSet set1 = new BarDataSet(values, "Data Set");
set1.setColors(ColorTemplate.VORDIPLOM_COLORS);
set1.setDrawValues(false);
// 图表数据集合
ArrayList dataSets = new ArrayList<>();
dataSets.add(set1);
// 填充图表数据
BarData data = new BarData(dataSets);
chart.setData(data);
chart.setFitBars(true);
// 刷新图表UI
chart.invalidate();
}
三 饼状图表
3.1 效果
3.2 xml里面增加饼状组件PieChart
3.3 Activity里面配置参数和数据
public class PieCharActivity extends Activity {
private PieChart chart;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pie_chart);
//饼状图控件
chart = findViewById(R.id.chart1);
//初始化饼状组件
initChart();
}
private void initChart(){
//是否用于百分比数据
chart.setUsePercentValues(true);
chart.getDescription().setEnabled(false);
chart.setExtraOffsets(5, 10, 5, 5);
chart.setDragDecelerationFrictionCoef(0.95f);
//设置中间文本的字体
//chart.setCenterTextTypeface(tfLight);
//chart.setCenterText(generateCenterSpannableText());
//是否绘制中心圆形区域和颜色
chart.setDrawHoleEnabled(true);
chart.setHoleColor(Color.WHITE);
//是否绘制中心边透明区域
chart.setTransparentCircleColor(Color.WHITE);
chart.setTransparentCircleAlpha(110);
//绘制中中心圆,和圆边的边框大小
chart.setHoleRadius(58f);
chart.setTransparentCircleRadius(61f);
//是否绘制中心区域文字
chart.setDrawCenterText(true);
//默认旋转角度
chart.setRotationAngle(0);
//通过触摸启用图表的旋转
chart.setRotationEnabled(true);
//触摸进行高亮的突出设置
chart.setHighlightPerTapEnabled(true);
//设置单位
// chart.setUnit(" €");
// chart.setDrawUnitsInChart(true);
//添加选择侦听器
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
//选中的扇页
}
@Override
public void onNothingSelected() {
//未选中的扇页
}
});
//动画
chart.animateY(1400, Easing.EaseInOutQuad);
// chart.spin(2000, 0, 360);
//图例
Legend l = chart.getLegend();
l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
l.setOrientation(Legend.LegendOrientation.VERTICAL);
l.setDrawInside(false);
l.setXEntrySpace(7f);
l.setYEntrySpace(0f);
l.setYOffset(0f);
//标签样式
chart.setEntryLabelColor(Color.WHITE);
//chart.setEntryLabelTypeface(tfRegular);
chart.setEntryLabelTextSize(12f);
//设置数据
setData();
}
//设置数据
private void setData() {
//二维数据的二级数据
ArrayList entries = new ArrayList<>();
//new PieEntry(数值,描述,图标icon)第一个
entries.add(new PieEntry(40.0f, "数据1", null));
entries.add(new PieEntry(20.0f, "数据2", null));
entries.add(new PieEntry(30.0f, "数据3", null));
entries.add(new PieEntry(10.0f, "数据4", null));
//二维数据的一级数据
PieDataSet dataSet = new PieDataSet(entries, "Election Results");
//数据配置,是否绘制图标
dataSet.setDrawIcons(false);
//扇页之间的空白间距
dataSet.setSliceSpace(3f);
//图标偏移
dataSet.setIconsOffset(new MPPointF(0, 40));
dataSet.setSelectionShift(5f);
//添加颜色集合,
ArrayList colors = new ArrayList<>();
//colors.add(ColorTemplate.LIBERTY_COLORS[0]);
colors.add(Color.parseColor("#3790A2"));
colors.add(Color.parseColor("#37F0A2"));
colors.add(Color.parseColor("#49DBEE"));
colors.add(Color.parseColor("#43C088"));
dataSet.setColors(colors);
//dataSet.setSelectionShift(0f);
//设置图表数据
PieData data = new PieData(dataSet);
data.setValueFormatter(new PercentFormatter());
data.setValueTextSize(11f);
data.setValueTextColor(Color.WHITE);
//data.setValueTypeface(tfLight);
chart.setData(data);
//撤消所有高光
chart.highlightValues(null);
//刷新图表UI
chart.invalidate();
}
}
四 折线图
4.1 效果
4.2 xml添加折线组件
4.3 Activity配置折现参数和数据
public class LineChartActivity extends Activity {
private LineChart chart;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_line_chart);
//折线图表组件
chart = findViewById(R.id.chart1);
//初始化图表
initChart();
}
//初始化图表
private void initChart(){
//点击监听
//chart.setOnChartValueSelectedListener(this);
//绘制网格线
chart.setDrawGridBackground(false);
//描述文本
chart.getDescription().setEnabled(false);
//是否可以触摸
chart.setTouchEnabled(true);
//启用缩放和拖动
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
// 如果禁用,可以分别在x轴和y轴上进行缩放
chart.setPinchZoom(true);
//设置背景色
// chart.setBackgroundColor(Color.GRAY);
//创建自定义MarkerView(扩展MarkerView)并指定布局
//MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view);
//mv.setChartView(chart); // For bounds control
//chart.setMarker(mv); // Set the marker to the chart
//配置x坐标数据
XAxis xl = chart.getXAxis();
xl.setAvoidFirstLastClipping(true);
xl.setAxisMinimum(0f);
//配置y坐标左边数据
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setInverted(true);
leftAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
//关闭y坐标右边数据
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
//抑制最大比例因子
// chart.setScaleMinima(3f, 3f);
//将视图居中到图表中的特定位置
// chart.centerViewPort(10, 50);
//图例
Legend l = chart.getLegend();
//修改图例
l.setForm(Legend.LegendForm.LINE);
setData();
}
private void setData() {
//二维数组 一级数据
ArrayList entries = new ArrayList<>();
for (int i = 0; i < 10; i++) {
float xVal = (i+1);
float yVal = (float) (Math.random() * 100);
entries.add(new Entry(xVal, yVal));
}
//通过x坐标值排序
Collections.sort(entries, new EntryXComparator());
//二维数组 二级数据
LineDataSet set1 = new LineDataSet(entries, "DataSet 1");
//折现的宽度合折点的半径大小
set1.setLineWidth(1.5f);
set1.setCircleRadius(4f);
//使用数据集创建数据对象
LineData data = new LineData(set1);
chart.setData(data);
//刷新绘图
chart.invalidate();
}
}
五 进阶饼状图和折线图,配置双折线和渐变区域
5.1 效果图
5.2 xml布局添加饼状和折线组件
5.4 Activity配置数据
public abstract class BaseActivity extends AppCompatActivity {
private ActivityBaseBinding activityBaseBinding;
public Binding mDataBinding;
public Activity mContext;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
activityBaseBinding=DataBindingUtil.setContentView(this, R.layout.activity_base);
initLayoutView();
}
private void initLayoutView() {
activityBaseBinding.vBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
StatuesBarUtils.setAppBar(this, true, R.color.white);
mDataBinding = DataBindingUtil.inflate(getLayoutInflater(), getLayoutId(),
activityBaseBinding.vContainer, true);
initData();
}
public void hideTitleLayout() {
StatuesBarUtils.setNoAppBar(this, true);
activityBaseBinding.vTitleLayout.setVisibility(View.GONE);
}
public void hideTitleLayout(View viewStatues) {
StatuesBarUtils.setNoAppBar(this, true);
activityBaseBinding.vTitleLayout.setVisibility(View.GONE);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) viewStatues.getLayoutParams();
layoutParams.height = StatuesBarUtils.getStatusHeight(mContext);
viewStatues.setLayoutParams(layoutParams);
}
public void setTitleText(String text) {
activityBaseBinding.vHeadTitle.setText(text);
}
protected abstract int getLayoutId();
public abstract void initData();
}
public class StatisticsActivity extends BaseActivity {
private LineChart chart;//折线图
private PieChart pieChart;//饼状图
@Override
protected int getLayoutId() {
return R.layout.activity_statistics;
}
@Override
public void initData() {
hideTitleLayout(mDataBinding.viewStatues);
mDataBinding.vBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
mDataBinding.vDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
initDatePicker();
}
});
//饼状图组件
pieChart = mDataBinding.vPieChart;
initChartPie();
//折线图组件
chart = mDataBinding.vLineChart;
initLineChar();
}
//初始化饼状图
private void initChartPie() {
//百分比数据
pieChart.setUsePercentValues(true);
//关闭描述
pieChart.getDescription().setEnabled(false);
//设置四周间距
pieChart.setExtraOffsets(5, 10, 5, 5);
//拖动旋转摩擦系数
pieChart.setDragDecelerationFrictionCoef(0.95f);
//中间文本
pieChart.setCenterText("");
//半透明区域
pieChart.setTransparentCircleColor(Color.WHITE);
pieChart.setTransparentCircleAlpha(110);
//中间白色圆环半径
pieChart.setHoleRadius(58f);
pieChart.setDrawHoleEnabled(false);
pieChart.setTransparentCircleRadius(61f);
pieChart.setDrawCenterText(true);
//旋转角度
pieChart.setRotationAngle(90);
//是否可以触摸旋转
pieChart.setRotationEnabled(true);
pieChart.setHighlightPerTapEnabled(true);
//单位
//chart.setUnit(" €");
//chart.setDrawUnitsInChart(true);
//选中监听
//chart.setOnChartValueSelectedListener(this);
pieChart.setEntryLabelColor(Color.BLACK);
//动画
pieChart.animateY(700, Easing.EaseInOutQuad);
//chart.spin(2000, 0, 360);
//图例
Legend l = pieChart.getLegend();
l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
l.setOrientation(Legend.LegendOrientation.VERTICAL);
l.setDrawInside(false);
l.setEnabled(false);
//设置饼状图数据
setPieData();
}
//设置饼状图数据
private void setPieData() {
//二维数组 二级数据
ArrayList entries = new ArrayList<>();
entries.add(new PieEntry(51.0f, "掃碼", null));
entries.add(new PieEntry(23.0f, "歷史價格", null));
entries.add(new PieEntry(39.0f, "個性二維碼", null));
//二维数组 一级数据
PieDataSet dataSet = new PieDataSet(entries, "Election Results");
//扇页之间间距
//dataSet.setSliceSpace(3f);
//dataSet.setSelectionShift(5f);
//添加颜色
ArrayList colors = new ArrayList<>();
colors.add(Color.parseColor("#37F0A2"));
colors.add(Color.parseColor("#49DBEE"));
colors.add(Color.parseColor("#43C088"));
dataSet.setColors(colors);
//设置百分比线的位置,分别是拐角,长线和短线
dataSet.setValueLinePart1OffsetPercentage(80.f);
dataSet.setValueLinePart1Length(0.3f);
dataSet.setValueLinePart2Length(0.7f);
//设置百分比线是在圆盘上还是圆盘外
//dataSet.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
//设置饼状数据
PieData data = new PieData(dataSet);
data.setValueFormatter(new PercentFormatter());
//data.setValueFormatter(new AssetsFormatter());
data.setValueTextSize(11f);
data.setValueTextColor(Color.BLACK);
pieChart.setData(data);
//取消高亮
pieChart.highlightValues(null);
//刷新UI
pieChart.invalidate();
}
//初始化折线配置
private void initLineChar() {
//选中监听
//chart.setOnChartValueSelectedListener(this);
//是否开启描述
chart.getDescription().setEnabled(false);
chart.setDescription(null);
//是否支持手势点击
chart.setTouchEnabled(true);
//拖动摩擦系数,即拖动流畅度
chart.setDragDecelerationFrictionCoef(0.9f);
//是否可以缩放和拖拽
chart.setDragEnabled(false);
chart.setScaleEnabled(false);
chart.setDrawGridBackground(false);
chart.setHighlightPerDragEnabled(true);
//如果禁用,可以分别在x轴和y轴上进行缩放
chart.setPinchZoom(true);
//背景颜色
chart.setBackgroundColor(Color.TRANSPARENT);
//动画
chart.animateX(700);
//无数据文案
chart.setNoDataText("暫無數據");
//四周间距
//chart.setViewPortOffsets(10, 0, 0,10);
//x轴配置
XAxis xAxis = chart.getXAxis();
//xAxis.setTypeface(tfLight);
xAxis.setTextSize(11f);
xAxis.setTextColor(Color.parseColor("#999999"));
xAxis.setDrawGridLines(false);
xAxis.setDrawAxisLine(false);
//x轴刻度位置
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setAxisLineColor(Color.parseColor("#ECECEC"));
xAxis.setGridColor(Color.parseColor("#ECECEC"));
//Y轴左边线配置
YAxis leftAxis = chart.getAxisLeft();
//leftAxis.setTypeface(tfLight);
leftAxis.setTextColor(Color.parseColor("#999999"));
leftAxis.setAxisMaximum(200f);
leftAxis.setAxisMinimum(0f);
leftAxis.setDrawGridLines(true);
leftAxis.setGranularityEnabled(false);
leftAxis.setAxisLineColor(Color.TRANSPARENT);
leftAxis.setGridColor(Color.parseColor("#ECECEC"));
//禁用y轴右边线
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
//图例
Legend legend = chart.getLegend();
legend.setEnabled(false);
//设置折线数据
setLineData();
}
//设置折线数据
private List allEntryList = new ArrayList<>();
private void setLineData() {
//二维数组 二级数据1
ArrayList values1 = new ArrayList<>();
values1.add(new Entry(0, 12f));
values1.add(new Entry(1, 29f));
values1.add(new Entry(2, 19f));
values1.add(new Entry(3, 25f));
values1.add(new Entry(4, 18f));
//二维数组 二级数据2
ArrayList values2 = new ArrayList<>();
values2.add(new Entry(0, 16f));
values2.add(new Entry(1, 33f));
values2.add(new Entry(2, 11f));
values2.add(new Entry(3, 20f));
values2.add(new Entry(4, 26f));
List lineDataSetList = new ArrayList<>();
//第一条折线的数据
if (values1.size() > 0) {
LineDataSet set1 = new LineDataSet(values1, null);
//创建数据集并为其指定类型
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
//折线颜色
set1.setColor(Color.parseColor("#35E5FF"));
//折线宽
set1.setLineWidth(2f);
//折点是否填充,即实心还是空心
set1.setFillAlpha(80);
//高亮颜色
set1.setHighLightColor(Color.TRANSPARENT);
//绘制圆形孔
set1.setDrawCircleHole(false);
//折点颜色
set1.setCircleColor(Color.parseColor("#FFBD02"));
//折点半径
set1.setCircleRadius(3f);
//格式化折点数据
//set1.setFillFormatter(new MyFillFormatter(0f));
//是否绘制水平方向的高亮线
set1.setDrawHorizontalHighlightIndicator(false);
//该条折线是否可见
//set1.setVisible(false);
//绘制平面填充区域
set1.setDrawFilled(true);
if (Utils.getSDKInt() >= 18) {
//仅在api级别18及以上版本上支持drawinables,渐变色drawable
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.line_fade_1);
set1.setFillDrawable(drawable);
} else {
//纯色
set1.setFillColor(Color.parseColor("#35E5FF"));
}
//添加所有折线的集合
lineDataSetList.add(set1);
}
//第二条折线的数据
if (values2.size() > 0) {
LineDataSet set2 = new LineDataSet(values2, null);
set2.setAxisDependency(YAxis.AxisDependency.RIGHT);
set2.setColor(Color.parseColor("#FFBD02"));
set2.setCircleColor(Color.parseColor("#35E5FF"));
set2.setLineWidth(2f);
set2.setCircleRadius(3f);
set2.setFillAlpha(80);
set2.setDrawFilled(true);
set2.setDrawCircleHole(false);
set2.setHighLightColor(Color.TRANSPARENT);
if (Utils.getSDKInt() >= 18) {
//仅在api级别18及以上版本上支持drawinables,渐变色drawable
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.line_fade_2);
set2.setFillDrawable(drawable);
} else {
set2.setFillColor(Color.parseColor("#FFBD02"));
}
lineDataSetList.add(set2);
}
//设置总数据
if (lineDataSetList.size() > 0) {
LineDataSet[] lineDataSets = lineDataSetList.toArray(new LineDataSet[lineDataSetList.size()]);
LineData data = new LineData(lineDataSets);
data.setValueTextColor(Color.TRANSPARENT);
data.setValueTextSize(9f);
//这是折线数据
chart.setData(data);
//设置x轴值
chart.getXAxis().setLabelCount(values1.size(), true);
chart.getXAxis().setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
String[] monthArray = new String[]{"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
int index = (int) value;
return monthArray[index];
}
});
//设置Y最大值
allEntryList.clear();
allEntryList.addAll(values1);
allEntryList.addAll(values2);
List floatYList = new ArrayList<>();
for (Entry entry : allEntryList) {
floatYList.add(entry.getY());
}
if (allEntryList.size() > 0) {
//设置Y轴最大设置范围和格式化数据
chart.getAxisLeft().setAxisMaximum(Collections.max(floatYList) + 10);
chart.getAxisLeft().setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float v) {
return String.valueOf(v);
}
});
}
} else {
chart.setData(null);
}
//刷新图表
chart.invalidate();
}
}
六 折线图进阶,添加平均值限制线
6.1 效果图
6.2 直接上配置吧
package com.xixia.chart;
import android.content.Context;
import android.graphics.Color;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
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.IndexAxisValueFormatter;
import com.github.mikephil.charting.utils.ColorTemplate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* @ClassName LineChartViewUtils
* @Description TODO 内容
* @Author biekangdong
* @CreateDate 2023/5/25 21:28
* @Version 1.0
* @UpdateDate 2023/5/25 21:28
* @UpdateRemark 更新说明
*/
public class LineChartViewUtils {
private Context context;
public LineChartViewUtils(Context context) {
this.context=context;
}
//配置折线数据
private void initChart(LineChart chart) {
//关闭描述
chart.getDescription().setEnabled(false);
//关闭高亮
chart.setHighlightPerDragEnabled(false);
//关闭图例
Legend l = chart.getLegend();
l.setEnabled(false);
//x轴数据
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTH_SIDED);
xAxis.setTextSize(10f);
xAxis.setTextColor(Color.parseColor("#999999"));
xAxis.setDrawAxisLine(true);
xAxis.setAxisLineColor(Color.parseColor("#DADADA"));
xAxis.setAxisLineWidth(0.5f);
xAxis.setDrawGridLines(true);
xAxis.setGridColor(Color.parseColor("#DADADA"));
xAxis.setGridLineWidth(0.5f);
chart.getXAxis().setValueFormatter(indexAxisValueFormatter);
//Y轴数据
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setEnabled(true);
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
leftAxis.setTextColor(Color.TRANSPARENT);
leftAxis.setDrawGridLines(false);
leftAxis.setDrawAxisLine(false);
//最小Y轴
//leftAxis.setAxisMinimum(0f);
//最大Y轴
//leftAxis.setAxisMaximum(170f);
//Y轴偏移
//leftAxis.setYOffset(-9f);
//关闭右边Y轴数值显示
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(true);
rightAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
rightAxis.setTextColor(Color.TRANSPARENT);
rightAxis.setDrawGridLines(false);
rightAxis.setDrawAxisLine(false);
}
int position = 0;
//时间格式化
SimpleDateFormat mFormatHour = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
SimpleDateFormat mFormatMonth = new SimpleDateFormat("MM/dd", Locale.ENGLISH);
SimpleDateFormat mFormatYear = new SimpleDateFormat("MM", Locale.ENGLISH);
IndexAxisValueFormatter indexAxisValueFormatter = new IndexAxisValueFormatter() {
@Override
public String getFormattedValue(float value) {
String valueString = "";
long millis = System.currentTimeMillis();
switch (position) {
case 0:
case 1:
valueString = mFormatHour.format(new Date(millis));
break;
case 2:
valueString = getWeekOfDate(millis);
break;
case 3:
valueString = mFormatMonth.format(new Date(millis));
break;
case 4:
valueString = mFormatYear.format(new Date(millis));
break;
}
return valueString;
}
};
//根据时间戳获取星期
public static String getWeekOfDate(long timestamp) {
String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(timestamp));
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
return weekDays[w];
}
//设置数据
public void setCharDataList(LineChart chart, ArrayList entryList, List valueList, float allValue, String unit) {
//平均值
float average = allValue / 10;
LimitLine limitLine = new LimitLine(average, average + unit + " 平均");
limitLine.enableDashedLine(10f, 10f, 0f);
if (Collections.max(valueList) - average > 0.3) {
limitLine.setLabelPosition(LimitLine.LimitLabelPosition.LEFT_TOP);
} else {
limitLine.setLabelPosition(LimitLine.LimitLabelPosition.LEFT_BOTTOM);
}
limitLine.setTextSize(10f);
limitLine.setLineColor(Color.parseColor("#6b9cdf"));
limitLine.setLineWidth(0.5f);
limitLine.setTextSize(10);
limitLine.setTextColor(Color.parseColor("#6b9cdf"));
limitLine.setYOffset(10);
//Y轴左右平均值数据
YAxis leftAxis = chart.getAxisLeft();
YAxis rightAxis = chart.getAxisRight();
leftAxis.removeAllLimitLines();
rightAxis.removeAllLimitLines();
leftAxis.setDrawLimitLinesBehindData(true);
rightAxis.setDrawLimitLinesBehindData(true);
//Y轴左右添加平均线
leftAxis.addLimitLine(limitLine);
rightAxis.addLimitLine(limitLine);
//填充数据
LineDataSet set1 = new LineDataSet(entryList, "DataSet 1");
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
set1.setColor(ColorTemplate.getHoloBlue());
set1.setValueTextColor(ColorTemplate.getHoloBlue());
set1.setLineWidth(1f);
set1.setDrawCircles(false);
set1.setDrawValues(false);
set1.setFillAlpha(65);
set1.setFillColor(Color.parseColor("#6b9cdf"));
set1.setHighLightColor(Color.parseColor("#6b9cdf"));
set1.setDrawCircleHole(false);
//使用数据集创建数据对象
LineData data = new LineData(set1);
data.setValueTextColor(Color.WHITE);
data.setValueTextSize(9f);
//这是折线数据
chart.setData(data);
//动画
//chart.animateX(1000);
//chart.animateY(1000);
//更新图表UI
chart.invalidate();
}
//点击事件
private void onViewClick(){
setData(0);
}
//设置温度,湿度,华氏度图表数据
public void setData(int tabSelectPosition) {
//温度℃
ArrayList valuesTemperature = new ArrayList<>();//温度图表数据
float allValueTemperature = 0;//温度平均值
List temperatureList = new ArrayList<>();//温度集合
//温度F
ArrayList valuesTemperatureFF = new ArrayList<>();//温度图表数据
float allValueTemperatureFF = 0;//温度平均值
List temperatureListFF = new ArrayList<>();//温度集合
//湿度
ArrayList valuesHumidity = new ArrayList<>();//湿度图表数据
float allValueHumidity = 0;//湿度平均值
List humidityList = new ArrayList<>();//湿度集合
//温度合集
List list = new ArrayList<>();
list.add("50");
list.add("20");
list.add("40");
list.add("60");
list.add("40");
list.add("30");
for (int i = 0; i < list.size(); i++) {
String temperature = list.get(i);
String humidity = String.valueOf(Math.random());
//温度℃
temperatureList.add(Float.valueOf(temperature));
allValueTemperature += Float.parseFloat(temperature);
valuesTemperature.add(new Entry(i, Float.parseFloat(temperature)));
//温度℉
temperatureListFF.add(Float.valueOf(temperature) * 1.8f + 32);
allValueTemperatureFF += Float.parseFloat(temperature) * 1.8f + 32;
valuesTemperatureFF.add(new Entry(i, Float.parseFloat(temperature) * 1.8f + 32));
//湿度
humidityList.add(Float.valueOf(humidity));
allValueHumidity += Float.parseFloat(humidity);
valuesHumidity.add(new Entry(i, Float.parseFloat(humidity)));
}
int positon = 0;
switch (positon) {
case 0:
setCharDataList(new LineChart(context), valuesTemperatureFF, temperatureListFF, allValueTemperatureFF, "℉");
break;
case 1:
setCharDataList(new LineChart(context), valuesTemperature, temperatureList, allValueTemperature, "℃");
break;
case 2:
setCharDataList(new LineChart(context), valuesHumidity, humidityList, allValueHumidity, "%");
break;
}
}
}
七 圆环进度图表,带圆角和不带圆角
7.1 带圆角效果图
7.2 自定义圆环类,有圆角,上面第一个图的样式
public class CircleProgressView extends View {
private Paint mBackPaint, mProgPaint; // 绘制画笔
private RectF mRectF; // 绘制区域
private int[] mColorArray; // 圆环渐变色
private int mProgress; // 圆环进度(0-100)
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircularProgressView);
// 初始化背景圆环画笔
mBackPaint = new Paint();
mBackPaint.setStyle(Paint.Style.STROKE); // 只描边,不填充
mBackPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角
mBackPaint.setAntiAlias(true); // 设置抗锯齿
mBackPaint.setDither(true); // 设置抖动
mBackPaint.setStrokeWidth(typedArray.getDimension(R.styleable.CircularProgressView_backWidth, 5));
mBackPaint.setColor(typedArray.getColor(R.styleable.CircularProgressView_backColor, Color.LTGRAY));
// 初始化进度圆环画笔
mProgPaint = new Paint();
mProgPaint.setStyle(Paint.Style.STROKE); // 只描边,不填充
mProgPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角
mProgPaint.setAntiAlias(true); // 设置抗锯齿
mProgPaint.setDither(true); // 设置抖动
mProgPaint.setStrokeWidth(typedArray.getDimension(R.styleable.CircularProgressView_progWidth, 10));
mProgPaint.setColor(typedArray.getColor(R.styleable.CircularProgressView_progColor, Color.BLUE));
// 初始化进度圆环渐变色
int startColor = typedArray.getColor(R.styleable.CircularProgressView_progStartColor, -1);
int firstColor = typedArray.getColor(R.styleable.CircularProgressView_progFirstColor, -1);
if (startColor != -1 && firstColor != -1) mColorArray = new int[]{startColor, firstColor};
else mColorArray = null;
// 初始化进度
mProgress = typedArray.getInteger(R.styleable.CircularProgressView_progress, 0);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int viewWide = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
int viewHigh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
int mRectLength = (int) ((viewWide > viewHigh ? viewHigh : viewWide) - (mBackPaint.getStrokeWidth() > mProgPaint.getStrokeWidth() ? mBackPaint.getStrokeWidth() : mProgPaint.getStrokeWidth()));
int mRectL = getPaddingLeft() + (viewWide - mRectLength) / 2;
int mRectT = getPaddingTop() + (viewHigh - mRectLength) / 2;
mRectF = new RectF(mRectL, mRectT, mRectL + mRectLength, mRectT + mRectLength);
// 设置进度圆环渐变色
if (mColorArray != null && mColorArray.length > 1)
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mRectF, 0, 360, false, mBackPaint);
canvas.drawArc(mRectF, 275, 360 * mProgress / 100, false, mProgPaint);
}
// ---------------------------------------------------------------------------------------------
/**
* 获取当前进度
*
* @return 当前进度(0-100)
*/
public int getProgress() {
return mProgress;
}
/**
* 设置当前进度
*
* @param progress 当前进度(0-100)
*/
public void setProgress(int progress) {
this.mProgress = progress;
invalidate();
}
/**
* 设置当前进度,并展示进度动画。如果动画时间小于等于0,则不展示动画
*
* @param progress 当前进度(0-100)
* @param animTime 动画时间(毫秒)
*/
public void setProgress(int progress, long animTime) {
if (animTime <= 0) setProgress(progress);
else {
ValueAnimator animator = ValueAnimator.ofInt(mProgress, progress);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (int) animation.getAnimatedValue();
invalidate();
}
});
animator.setInterpolator(new OvershootInterpolator());
animator.setDuration(animTime);
animator.start();
}
}
/**
* 设置背景圆环宽度
*
* @param width 背景圆环宽度
*/
public void setBackWidth(int width) {
mBackPaint.setStrokeWidth(width);
invalidate();
}
/**
* 设置背景圆环颜色
*
* @param color 背景圆环颜色
*/
public void setBackColor(@ColorRes int color) {
mBackPaint.setColor(ContextCompat.getColor(getContext(), color));
invalidate();
}
/**
* 设置进度圆环宽度
*
* @param width 进度圆环宽度
*/
public void setProgWidth(int width) {
mProgPaint.setStrokeWidth(width);
invalidate();
}
/**
* 设置进度圆环颜色
*
* @param color 景圆环颜色
*/
public void setProgColor(@ColorRes int color) {
mProgPaint.setColor(ContextCompat.getColor(getContext(), color));
mProgPaint.setShader(null);
invalidate();
}
/**
* 设置进度圆环颜色(支持渐变色)
*
* @param startColor 进度圆环开始颜色
* @param firstColor 进度圆环结束颜色
*/
public void setProgColor(@ColorRes int startColor, @ColorRes int firstColor) {
mColorArray = new int[]{ContextCompat.getColor(getContext(), startColor), ContextCompat.getColor(getContext(), firstColor)};
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
invalidate();
}
/**
* 设置进度圆环颜色(支持渐变色)
*
* @param colorArray 渐变色集合
*/
public void setProgColor(@ColorRes int[] colorArray) {
if (colorArray == null || colorArray.length < 2) return;
mColorArray = new int[colorArray.length];
for (int index = 0; index < colorArray.length; index++)
mColorArray[index] = ContextCompat.getColor(getContext(), colorArray[index]);
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
invalidate();
}
}
使用:
xml添加控件
java设置圆环进度:
CircleProgressView cpProgress = (CircleProgressView) findViewById(R.id.cp_progress);
cpProgress.setProgress((int) (30/60f*100));
7.3 不带圆角效果图
7.4 xml添加组件
java设置进度
CircleProgressView cpProgress = (CircleProgressView) findViewById(R.id.cp_progress);
cpProgress.setProgress((int) (30/80f*100));
八 仪表图
8.1 效果图
8.2 自定义仪表盘View
public class DashboardView3 extends BaseDashboardView {
//外环画笔
private Paint mPaintOuterArc;
//内环画笔
private Paint mPaintInnerArc;
//进度点画笔
private Paint mPaintProgressPoint;
//指示器画笔
private Paint mPaintIndicator;
//外环区域
private RectF mRectOuterArc;
//内环区域
private RectF mRectInnerArc;
//圆环画笔颜色
private int mOuterArcColor;
private int mProgressOuterArcColor;
//内环画笔颜色
private int mInnerArcColor;
private int mProgressInnerArcColor;
//内外环之间的间距
private float mArcSpacing;
//进度条的圆点属性
private float[] mProgressPointPosition;
private float mProgressPointRadius;
//指标器的Path
private Path mIndicatorPath;
//指示器的起始位置
private float mIndicatorStart;
//默认圆环之间间距
private static final float DEFAULT_ARC_SPACING = 10;
//外环的默认属性
private static final float DEFAULT_OUTER_ARC_WIDTH = 1.5f;
private static final int DEFAULT_OUTER_ARC_COLOR = Color.argb(80, 255, 255, 255);
//外环进度的默认属性
private static final int DEFAULT_PROGRESS_OUTER_ARC_COLOR = Color.argb(200, 255, 255, 255);
//进度点的默认属性
private static final float DEFAULT_PROGRESS_POINT_RADIUS = 3;
private static final int DEFAULT_PROGRESS_POINT_COLOR = Color.WHITE;
//内环默认属性
private static final float DEFAULT_INNER_ARC_WIDTH = 1.5f;
private static final int DEFAULT_INNER_ARC_COLOR = Color.argb(50, 255, 255, 255);
//内环进度的默认属性
private static final int DEFAULT_PROGRESS_INNER_ARC_COLOR = Color.argb(170, 255, 255, 255);
//指示器默认属性
private static final int DEFAULT_INDICATOR_COLOR = Color.argb(200, 255, 255, 255);
public DashboardView3(Context context) {
this(context, null);
}
public DashboardView3(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DashboardView3(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 初始化界面
*/
@Override
protected void initView() {
//默认数据
mArcSpacing = dp2px(DEFAULT_ARC_SPACING);
mOuterArcColor = DEFAULT_OUTER_ARC_COLOR;
mProgressOuterArcColor = DEFAULT_PROGRESS_OUTER_ARC_COLOR;
mProgressPointRadius = dp2px(DEFAULT_PROGRESS_POINT_RADIUS);
mInnerArcColor = DEFAULT_INNER_ARC_COLOR;
mProgressInnerArcColor = DEFAULT_PROGRESS_INNER_ARC_COLOR;
//初始化画笔
//外环画笔
mPaintOuterArc = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintOuterArc.setStrokeWidth(dp2px(DEFAULT_OUTER_ARC_WIDTH));
mPaintOuterArc.setStyle(Paint.Style.STROKE);
//内环画笔
mPaintInnerArc = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintInnerArc.setStrokeWidth(dp2px(DEFAULT_INNER_ARC_WIDTH));
mPaintInnerArc.setStyle(Paint.Style.STROKE);
mPaintInnerArc.setStrokeCap(Paint.Cap.ROUND);
PathEffect mPathEffect = new DashPathEffect(new float[] { 10, 10 }, 0);
mPaintInnerArc.setPathEffect(mPathEffect);
//进度点画笔
mPaintProgressPoint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintProgressPoint.setStyle(Paint.Style.FILL);
mPaintProgressPoint.setColor(DEFAULT_PROGRESS_POINT_COLOR);
//指示器画笔
mPaintIndicator = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintIndicator.setStrokeCap(Paint.Cap.SQUARE);
mPaintIndicator.setColor(DEFAULT_INDICATOR_COLOR);
mPaintIndicator.setStrokeWidth(dp2px(1));
//进度点的图片
mProgressPointPosition = new float[2];
}
/**
* 初始化圆环区域
*/
@Override
protected void initArcRect(float left, float top, float right, float bottom) {
//外环区域
mRectOuterArc = new RectF(left, top, right, bottom);
initInnerRect();
}
/**
* 初始化内部的区域
*/
private void initInnerRect() {
//内环位置
mRectInnerArc = new RectF(mRectOuterArc.left + mArcSpacing,mRectOuterArc.top + mArcSpacing,
mRectOuterArc.right - mArcSpacing , mRectOuterArc.bottom - mArcSpacing);
//指标器的路径
mIndicatorStart = mRectInnerArc.top + mArcSpacing / 2;
mIndicatorPath = new Path();
mIndicatorPath.moveTo(mRadius, mIndicatorStart);
mIndicatorPath.rLineTo(-dp2px(2), dp2px(5));
mIndicatorPath.rLineTo(dp2px(4), 0);
mIndicatorPath.close();
}
/**
* 绘制圆环
*/
@Override
protected void drawArc(Canvas canvas, float arcStartAngle, float arcSweepAngle) {
//绘制圆环
mPaintOuterArc.setColor(mOuterArcColor);
canvas.drawArc(mRectOuterArc, arcStartAngle, arcSweepAngle, false, mPaintOuterArc);
//绘制内环
mPaintInnerArc.setColor(mInnerArcColor);
canvas.drawArc(mRectInnerArc, arcStartAngle, arcSweepAngle, false, mPaintInnerArc);
}
/**
* 绘制进度圆环
*/
@Override
protected void drawProgressArc(Canvas canvas, float arcStartAngle, float progressSweepAngle) {
//绘制进度点
if(progressSweepAngle == 0) {
return;
}
Path path = new Path();
//添加进度圆环的区域
path.addArc(mRectOuterArc, arcStartAngle, progressSweepAngle);
//计算切线值和为重
PathMeasure pathMeasure = new PathMeasure(path, false);
pathMeasure.getPosTan(pathMeasure.getLength(), mProgressPointPosition, null);
//绘制圆环
mPaintOuterArc.setColor(mProgressOuterArcColor);
canvas.drawPath(path, mPaintOuterArc);
//绘制进度点
if(mProgressPointPosition[0] != 0 && mProgressPointPosition[1] != 0) {
canvas.drawCircle(mProgressPointPosition[0], mProgressPointPosition[1], mProgressPointRadius, mPaintProgressPoint);
}
//绘制内环
mPaintInnerArc.setColor(mProgressInnerArcColor);
canvas.drawArc(mRectInnerArc, arcStartAngle, progressSweepAngle, false, mPaintInnerArc);
//绘制指针
canvas.save();
canvas.rotate(arcStartAngle + progressSweepAngle - 270, mRadius, mRadius);
mPaintIndicator.setStyle(Paint.Style.FILL);
canvas.drawPath(mIndicatorPath, mPaintIndicator);
mPaintIndicator.setStyle(Paint.Style.STROKE);
canvas.drawCircle(mRadius, mIndicatorStart + dp2px(6) + 1, dp2px(2), mPaintIndicator);
canvas.restore();
}
/**
* 绘制文字
*/
@Override
protected void drawText(Canvas canvas, int value, String valueLevel, String currentTime) {
//绘制数值
float marginTop = mRadius + mTextSpacing;
canvas.drawText(String.valueOf(value), mRadius, marginTop, mPaintValue);
//绘制数值文字信息
if(!TextUtils.isEmpty(valueLevel)){
float margin = mRadius - mTextSpacing - getPaintHeight(mPaintValue, "9");
canvas.drawText(valueLevel, mRadius, margin, mPaintValueLevel);
}
//绘制日期
if(!TextUtils.isEmpty(currentTime)) {
marginTop = marginTop + getPaintHeight(mPaintDate, currentTime) + mTextSpacing;
canvas.drawText(currentTime, mRadius, marginTop, mPaintDate);
}
}
/**
* 设置圆环的距离
*/
public void setArcSpacing(float dpSize){
mArcSpacing = dp2px(dpSize);
initInnerRect();
postInvalidate();
}
/**
* 设置外环颜色
*/
public void setOuterArcPaint(float dpSize, @ColorInt int color){
mPaintOuterArc.setStrokeWidth(dp2px(dpSize));
mOuterArcColor = color;
postInvalidate();
}
/**
* 设置进度条的颜色
*/
public void setProgressOuterArcColor(@ColorInt int color){
mProgressOuterArcColor = color;
postInvalidate();
}
/**
* 设置内环的属性
*/
public void setInnerArcPaint(float dpSize, @ColorInt int color){
mPaintInnerArc.setStrokeWidth(dp2px(dpSize));
mInnerArcColor = color;
postInvalidate();
}
/**
* 设置内环的属性
*/
public void setProgressInnerArcPaint(@ColorInt int color){
mProgressInnerArcColor = color;
postInvalidate();
}
/**
* 设置内环实线和虚线状态
*/
public void setInnerArcPathEffect(float[] intervals){
PathEffect mPathEffect = new DashPathEffect(intervals, 0);
mPaintInnerArc.setPathEffect(mPathEffect);
postInvalidate();
}
/**
* 设置进度圆点的属性
*/
public void setProgressPointPaint(float dpRadiusSize,@ColorInt int color){
mProgressPointRadius = dp2px(dpRadiusSize);
mPaintProgressPoint.setColor(color);
postInvalidate();
}
/**
* 设置指示器属性
*/
public void setIndicatorPaint(@ColorInt int color){
mPaintIndicator.setColor(color);
postInvalidate();
}
}
8.3 使用:
DashboardView3 dashboardView= findViewById(R.id.dv);
dashboardView.setDateStrPattern("评估时间:2023-05-25");
dashboardView.setValueLevelPattern("信用优秀");
int max = dashboardView.getMax();
int min = dashboardView.getMin();
dashboardView.setValue(new Random().nextInt(max - min) + min, anim, reset);