Android 之MPAndroidChart图表案例

一 简介

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

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.github.mikephil.charting.charts.BarChart
        android:id="@+id/chart1"
        android:layout_width="match_parent"
        android:layout_height="300dp" />
    
</FrameLayout>

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<BarEntry> 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<IBarDataSet> 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

<?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">
    <com.github.mikephil.charting.charts.PieChart
        android:id="@+id/chart1"
        android:layout_width="match_parent"
        android:layout_height="300dp" />
</LinearLayout>

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<PieEntry> 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<Integer> 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添加折线组件

<?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:orientation="vertical">
    <com.github.mikephil.charting.charts.PieChart
        android:id="@+id/chart1"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:layout_height="300dp" />
</LinearLayout>

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<Entry> 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布局添加饼状和折线组件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <View
            android:id="@+id/view_statues"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:background="@color/white" />

        <RelativeLayout
            android:id="@+id/v_title_layout"
            android:layout_width="match_parent"
            android:layout_height="44dp"
            android:background="@color/white">


            <ImageView
                android:id="@+id/v_back"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:src="@mipmap/ic_back" />

            <LinearLayout
                android:id="@+id/v_date"
                android:layout_width="wrap_content"
                android:layout_height="34dp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="20dp"
                android:background="@drawable/shape_bg_welcom_gradient"
                android:gravity="center"
                android:paddingLeft="7dp"
                android:paddingRight="7dp">

                <TextView
                    android:id="@+id/tv_date"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="2022.05"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/down_white" />
            </LinearLayout>
        </RelativeLayout>

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_marginLeft="20dp"
                    android:layout_marginTop="7dp"
                    android:gravity="center_vertical"
                    android:text="統計"
                    android:textColor="@color/color_text_title"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_marginLeft="20dp"
                    android:layout_marginTop="18dp"
                    android:gravity="center_vertical"
                    android:text="記錄"
                    android:textColor="@color/color_text_title"
                    android:textSize="20sp" />

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="18dp"
                    android:paddingLeft="20dp"
                    android:paddingRight="20dp">

                    <com.github.mikephil.charting.charts.PieChart
                        android:id="@+id/v_pie_chart"
                        android:layout_width="match_parent"
                        android:layout_height="228dp" />
                </FrameLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:paddingLeft="20dp"
                    android:paddingRight="20dp">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:drawableLeft="@drawable/shape_circle_tingji1"
                        android:drawablePadding="10dp"
                        android:gravity="center_vertical"
                        android:text="掃碼"
                        android:textColor="@color/color_text_title"
                        android:textSize="16sp" />

                    <View
                        android:layout_width="0dp"
                        android:layout_height="1dp"
                        android:layout_weight="1" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:drawableLeft="@drawable/shape_circle_tingji2"
                        android:drawablePadding="10dp"
                        android:gravity="center_vertical"
                        android:text="歷史價格"
                        android:textColor="@color/color_text_title"
                        android:textSize="16sp" />

                    <View
                        android:layout_width="0dp"
                        android:layout_height="1dp"
                        android:layout_weight="1" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:drawableLeft="@drawable/shape_circle_tingji3"
                        android:drawablePadding="10dp"
                        android:gravity="center_vertical"
                        android:text="個性二維碼"
                        android:textColor="@color/color_text_title"
                        android:textSize="16sp" />
                </LinearLayout>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_marginLeft="20dp"
                    android:layout_marginTop="20dp"
                    android:gravity="center_vertical"
                    android:text="訂單"
                    android:textColor="@color/color_text_title"
                    android:textSize="20sp" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:paddingLeft="20dp"
                    android:paddingRight="20dp">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:drawableLeft="@drawable/shape_circle_order1"
                        android:drawablePadding="8dp"
                        android:gravity="center_vertical"
                        android:text="未購買"
                        android:textColor="@color/color_text_title"
                        android:textSize="16sp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_marginLeft="20dp"
                        android:drawableLeft="@drawable/shape_circle_order2"
                        android:drawablePadding="8dp"
                        android:gravity="center_vertical"
                        android:text="已購買"
                        android:textColor="@color/color_text_title"
                        android:textSize="16sp" />
                </LinearLayout>

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:paddingLeft="20dp"
                    android:paddingRight="10dp"
                    android:layout_marginBottom="20dp">

                    <com.github.mikephil.charting.charts.LineChart
                       android:id="@+id/v_line_chart"
                        android:layout_width="match_parent"
                        android:layout_height="228dp" />
                </FrameLayout>
            </LinearLayout>
        </androidx.core.widget.NestedScrollView>
    </LinearLayout>

</layout>

5.4 Activity配置数据

public abstract class BaseActivity<Binding extends ViewDataBinding> 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<ActivityStatisticsBinding> {
    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<PieEntry> 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<Integer> 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<Entry> allEntryList = new ArrayList<>();

    private void setLineData() {
        //二维数组 二级数据1
        ArrayList<Entry> 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<Entry> 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<LineDataSet> 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<Float> 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<Entry> entryList, List<Float> 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<Entry> valuesTemperature = new ArrayList<>();//温度图表数据
        float allValueTemperature = 0;//温度平均值
        List<Float> temperatureList = new ArrayList<>();//温度集合
        //温度F
        ArrayList<Entry> valuesTemperatureFF = new ArrayList<>();//温度图表数据
        float allValueTemperatureFF = 0;//温度平均值
        List<Float> temperatureListFF = new ArrayList<>();//温度集合
        //湿度
        ArrayList<Entry> valuesHumidity = new ArrayList<>();//湿度图表数据
        float allValueHumidity = 0;//湿度平均值
        List<Float> humidityList = new ArrayList<>();//湿度集合

        //温度合集
        List<String> 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 布局文件xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <LinearLayout
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:background="@drawable/shape_bg_dfe9fe_bottom_50"
	android:gravity="center_horizontal"
	android:orientation="vertical">

	<View
		android:id="@+id/view_statues2"
		android:layout_width="match_parent"
		android:layout_height="0dp" />

	<View
		android:layout_width="match_parent"
		android:layout_height="44dp" />

	<TextView
		android:id="@+id/v_total_assets"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_centerInParent="true"
		android:layout_marginTop="24dp"
		android:text="¥ 28,529.08"
		android:textColor="@color/color_00020c"
		android:textSize="36sp"
		android:textStyle="bold" />

	<TextView
		android:id="@+id/v_loss_assets"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_centerInParent="true"
		android:layout_marginTop="8dp"
		android:text="-¥917.00"
		android:textColor="#E36767"
		android:textSize="18sp" />

	<com.github.mikephil.charting.charts.LineChart
		android:id="@+id/line_chart"
		android:layout_width="match_parent"
		android:layout_height="164dp"
		android:layout_marginTop="40dp"
		android:layout_marginBottom="16dp" />
</LinearLayout>
</layout>

7.3 自定义标记控件CustomMarkerView.java

public class CustomMarkerView extends MarkerView {
    private TextView textView;
    private IAxisValueFormatter iAxisValueFormatter;
    private DecimalFormat format;//数字格式化
    public CustomMarkerView(Context context,IAxisValueFormatter iAxisValueFormatter) {
        super(context,R.layout.custom_marker_view_layout);
        this.iAxisValueFormatter=iAxisValueFormatter;
        textView=(TextView)findViewById(R.id.contentview);
        format=new DecimalFormat("###.0");//定义数字格式
    }
    @Override
    //进行重绘
    public void refreshContent(Entry e, Highlight highlight) {
        textView.setText(format.format(e.getY()));
        super.refreshContent(e, highlight);
    }
    @Override
    public MPPointF getOffset() {
        return new MPPointF(-(getWidth()/2),-getHeight());
    }
}

7.4 配置

public class Fragment1{

  private void initLineChar() {
        chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {
                Highlight[] highlights=chart.getHighlighted();
                chart.highlightValues(highlights);
            }

            @Override
            public void onNothingSelected() {

            }
        });

        // no description text
        chart.getDescription().setEnabled(false);
        chart.setDescription(null);

        // enable touch gestures
        chart.setTouchEnabled(true);

        //chart.setDragDecelerationFrictionCoef(0.9f);

        // enable scaling and dragging
        chart.setDragEnabled(false);
        chart.setScaleEnabled(false);
        chart.setDrawGridBackground(false);
//        chart.setHighlightPerDragEnabled(true);
//        chart.setHighlightPerTapEnabled(true);

        // if disabled, scaling can be done on x- and y-axis separately
        //chart.setPinchZoom(true);

        CustomMarkerView marker=new CustomMarkerView(getActivity(), new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                return ""+value;
            }
        });
        marker.setChartView(chart);
        chart.setMarker(marker);

        // set an alternative background color
        chart.setBackgroundColor(Color.TRANSPARENT);

        chart.animateX(700);
        //chart.setNoDataText("No Data");

        XAxis xAxis = chart.getXAxis();
        //xAxis.setTypeface(tfLight);
        xAxis.setTextSize(11f);
        xAxis.setTextColor(Color.parseColor("#9999AA"));
        xAxis.setDrawGridLines(false);
        xAxis.setDrawAxisLine(true);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setAxisLineColor(Color.parseColor("#9999AA"));
        xAxis.setGridColor(Color.parseColor("#9999AA"));


        YAxis leftAxis = chart.getAxisLeft();

        leftAxis.setMaxWidth(0.01f);
        leftAxis.setMinWidth(0.01f);
        leftAxis.setDrawGridLines(false);
        leftAxis.setDrawAxisLine(true);
        leftAxis.setTextColor(Color.TRANSPARENT);
        leftAxis.setEnabled(true);
        leftAxis.setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
                return null;
            }
        });

        YAxis rightAxis = chart.getAxisRight();
        rightAxis.setTextColor(Color.parseColor("#9999AA"));
//        rightAxis.setDrawGridLines(true);
//        rightAxis.setGranularityEnabled(false);
        rightAxis.setAxisLineColor(getResources().getColor(R.color.color_9999aa));
        rightAxis.setGridColor(Color.parseColor("#9999AA"));


        //图例
        Legend legend = chart.getLegend();
        legend.setEnabled(false);

        setLineData();
    }



    private void setLineData() {
        ArrayList<Entry> values1 = new ArrayList<>();
        values1.add(new Entry(0, 0));
        values1.add(new Entry(1, 100000));
        values1.add(new Entry(2, 200000));
        values1.add(new Entry(3, 400000));
        values1.add(new Entry(4, 204000));

        updateData(values1);

    }

    private void updateData(ArrayList<Entry> values1) {
        if (values1.size() > 0) {
            LineDataSet set1 = new LineDataSet(values1, null);

            set1.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);

            // create a dataset and give it a type
//            set1.setAxisDependency(YAxis.AxisDependency.LEFT);
            set1.setColor(Color.parseColor("#9999AA"));
            set1.setCircleColor(Color.parseColor("#9999AA"));
            set1.setLineWidth(2f);
            set1.setCircleRadius(3f);
            set1.setFillAlpha(80);
            set1.setHighLightColor(Color.parseColor("#9999AA"));
            set1.setDrawHorizontalHighlightIndicator(false);
            set1.setDrawVerticalHighlightIndicator(true);

            set1.setHighlightEnabled(true);
            set1.setDrawCircleHole(false);
            set1.setDrawIcons(false);
            set1.setDrawCircles(false);
            set1.setDrawValues(true);
            set1.setDrawFilled(false);
            //set1.setFillFormatter(new MyFillFormatter(0f));
            //set1.setVisible(false);
            set1.setCircleHoleColor(Color.parseColor("#00020C"));

            LineData data = new LineData(set1);
            data.setDrawValues(false);
            //data.setValueTextColor(Color.parseColor("#FFBD02"));
            data.setValueTextSize(9f);
            data.setHighlightEnabled(true);


            // set data
            chart.setData(data);

//            chart.getAxisRight().setAxisMaximum(500000);
            chart.getAxisRight().setAxisMinimum(0f);
            chart.getAxisRight().setValueFormatter(new ValueFormatter() {

                @Override
                public String getFormattedValue(float value, AxisBase axis) {
                    return String.valueOf(value);

                }
            });

            //设置x轴值
            chart.getXAxis().setLabelCount(values1.size(), true);
            chart.getXAxis().setValueFormatter(new ValueFormatter() {
                @Override
                public String getFormattedValue(float value) {
                    String[] monthArray = new String[]{"D", "W", "M", "6M", "1Y"};
                    int index = (int) value;
                    return monthArray[index];
                }
            });
        }else {
            chart.setData(null);
        }


        chart.invalidate();
    }
}

八  圆环进度图表,带圆角和不带圆角

8.1  带圆角效果图

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

8.3 使用:

xml添加控件

 <RelativeLayout
        android:layout_width="177dp"
        android:layout_height="177dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="25dp"
        android:gravity="center_horizontal">

        <FrameLayout
            android:layout_width="177dp"
            android:layout_height="177dp">
            <View
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="4dp"
                android:background="@drawable/shape_bg_f2efff"/>
            <com.example.finance.CircleProgressView
                android:id="@+id/cp_progress"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:backColor="@color/trans"
                app:backWidth="8dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:progColor="@color/color_blue"
                app:progWidth="8dp"
                app:progress="0" />
        </FrameLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="24dp"
                android:text="BMI"
                android:textColor="#ff262729"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/tv_progress"
                android:layout_width="wrap_content"
                android:layout_height="24dp"
                android:text="0"
                android:textStyle="bold"
                android:textColor="#ff7783ff"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/tv_progress_value"
                android:layout_width="wrap_content"
                android:layout_height="16dp"
                android:text="你的体型很标准哦"
                android:textColor="#ff262729"
                android:layout_marginTop="13dp"
                android:textSize="12sp" />
        </LinearLayout>

    </RelativeLayout>

java设置圆环进度:

CircleProgressView cpProgress = (CircleProgressView) findViewById(R.id.cp_progress);
cpProgress.setProgress((int) (30/60f*100));

8.4 不带圆角效果图

 8.5 xml添加组件

 <androidx.cardview.widget.CardView
	android:id="@+id/cl_budget"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:layout_marginLeft="15dp"
	android:layout_marginTop="20dp"
	android:layout_marginRight="15dp"
	app:cardBackgroundColor="@color/white"
	app:cardCornerRadius="@dimen/dp_5"
	app:cardElevation="3dp">

	<androidx.constraintlayout.widget.ConstraintLayout
		android:layout_width="110dp"
		android:layout_height="110dp"
		android:layout_gravity="center_vertical"
		android:layout_marginLeft="20dp"
		android:layout_marginTop="25dp"
		android:layout_marginBottom="25dp">

		<com.dinghe.financeapp.utils.CircleProgressView
		   android:id="@+id/cp_progress"
			android:layout_width="0dp"
			android:layout_height="0dp"
			app:backColor="@color/color_d8d8d8"
			app:backWidth="8dp"
			app:layout_constraintBottom_toBottomOf="parent"
			app:layout_constraintLeft_toLeftOf="parent"
			app:layout_constraintRight_toRightOf="parent"
			app:layout_constraintTop_toTopOf="parent"
			app:progColor="@color/color_blue"
			app:progWidth="8dp"
			app:progress="0" />

		<TextView
			android:id="@+id/tv_progress"
			style="@style/Font_black"
			android:layout_centerInParent="true"
			android:text="0"
			android:textColor="@color/color_3d"
			android:textSize="24sp"
			android:textStyle="bold"
			app:layout_constraintBottom_toBottomOf="parent"
			app:layout_constraintLeft_toLeftOf="parent"
			app:layout_constraintRight_toRightOf="parent"
			app:layout_constraintTop_toTopOf="parent" />

		<TextView
			style="@style/Font_black"
			android:layout_marginLeft="4dp"
			android:layout_marginBottom="3dp"
			android:text="%"
			android:textColor="@color/color_3d"
			android:textSize="14sp"
			app:layout_constraintBottom_toBottomOf="@id/tv_progress"
			app:layout_constraintLeft_toRightOf="@id/tv_progress" />
	</androidx.constraintlayout.widget.ConstraintLayout>

	<LinearLayout
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_gravity="center_vertical"
		android:layout_marginLeft="140dp"
		android:layout_marginRight="15dp"
		android:orientation="vertical">

		<RelativeLayout
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:gravity="center_vertical">

			<TextView
				style="@style/Font_black"
				android:layout_centerVertical="true"
				android:text="@string/me_budget"
				android:textSize="17sp"
				android:textStyle="bold" />

			<ImageView
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:layout_alignParentRight="true"
				android:layout_centerVertical="true"
				android:src="@mipmap/ic_next2" />
		</RelativeLayout>

		<TextView
			android:id="@+id/tv_budget_amount"
			style="@style/Font_black"
			android:layout_marginTop="10dp"
			android:text="@string/me_budget_amount"
			android:textSize="14sp" />

		<TextView
			android:id="@+id/tv_budget_outlay"
			style="@style/Font_black"
			android:layout_marginTop="5dp"
			android:text="@string/me_budget_outlay"
			android:textSize="14sp" />

		<TextView
			android:id="@+id/tv_budget_balance"
			style="@style/Font_black"
			android:layout_marginTop="5dp"
			android:text="@string/me_budget_balance"
			android:textSize="14sp" />
	</LinearLayout>
</androidx.cardview.widget.CardView>

java设置进度

CircleProgressView cpProgress = (CircleProgressView) findViewById(R.id.cp_progress);
cpProgress.setProgress((int) (30/80f*100));

九 仪表图

9.1 效果图

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

9.3 使用:

<LinearLayout
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:background="@drawable/bg"
	android:gravity="center_horizontal">

	<com.github.iron.chart.dashboard.DashboardView3
		android:id="@+id/dv"
		android:layout_width="250dp"
		android:layout_height="180dp"
		android:layout_marginTop="30dp"
		android:layout_marginBottom="40dp" />
</LinearLayout>
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);
  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值