Android MPAndroidChart 自定义圆饼图扇形阴影颜色

效果展示

设计图

在这里插入图片描述

最终实现

在这里插入图片描述

要实现阴影效果需要自定义PieChartRenderer

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
import com.github.mikephil.charting.renderer.PieChartRenderer;
import com.github.mikephil.charting.utils.ViewPortHandler;

public class CustomPieChartRenderer extends PieChartRenderer {

    public CustomPieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
        super(chart, animator, viewPortHandler);
    }

    @Override
    protected void drawDataSet(Canvas c, IPieDataSet dataSet) {
        // 保存Canvas状态,防止状态污染
        c.save();

        // 获取总旋转角度
        float rotationAngle = mChart.getRotationAngle();

        // 获取饼图半径
        float radius = mChart.getRadius();

        // 获取总数据项的数量
        int entryCount = dataSet.getEntryCount();

        // 获取总的角度范围
        float totalAngle = 360f;

        // 手动计算数据集的总和
        float totalValue = 0f;
        for (int i = 0; i < entryCount; i++) {
            totalValue += dataSet.getEntryForIndex(i).getValue();
        }

        // 当前开始的角度
        float currentStartAngle = rotationAngle;

        // 遍历每个扇形
        for (int i = 0; i < entryCount; i++) {
            PieEntry entry = dataSet.getEntryForIndex(i);

            // 获取当前扇形的颜色
            int pieColor = dataSet.getColor(i);

            // 创建一个新的画笔,避免复用全局的Paint对象
            Paint renderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            Paint highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

            // 提亮当前颜色生成阴影颜色
            int lighterShadowColor = lightenColor(pieColor, 0.1f);

            // 设置普通画笔的颜色和阴影
            renderPaint.setColor(pieColor);
            renderPaint.setShadowLayer(40f, 0f, 0f, lighterShadowColor);

            // 计算当前扇形的角度,基于该项的值占总和的百分比
            float sliceAngle = totalAngle * (entry.getValue() / totalValue);

            // 判断当前扇形是否高亮
            if (isEntryHighlighted(i)) {
                // 每个高亮扇形的颜色和阴影
                highlightPaint.setColor(pieColor);
                highlightPaint.setShadowLayer(60f, 0f, 0f, lightenColor(pieColor, 0.1f));

                // 使用高亮画笔绘制高亮的扇形
                c.drawArc(
                        mChart.getCircleBox(),         // 饼图的圆形区域
                        currentStartAngle,             // 当前扇形的起始角度
                        sliceAngle,                    // 当前扇形的角度范围
                        true,                          // 是否使用圆心
                        highlightPaint                 // 使用高亮画笔
                );
            } else {
                // 使用普通画笔绘制普通的扇形
                c.drawArc(
                        mChart.getCircleBox(),         // 饼图的圆形区域
                        currentStartAngle,             // 当前扇形的起始角度
                        sliceAngle,                    // 当前扇形的角度范围
                        true,                          // 是否使用圆心
                        renderPaint                    // 使用普通画笔
                );
            }

            // 更新下一个扇形的起始角度
            currentStartAngle += sliceAngle;
        }

        // 恢复Canvas状态
        c.restore();
    }

    // 检查当前项是否是高亮项
    private boolean isEntryHighlighted(int index) {
        Highlight[] highlights = mChart.getHighlighted();
        if (highlights != null && highlights.length > 0) {
            for (Highlight highlight : highlights) {
                if ((int) highlight.getX() == index) {
                    return true;
                }
            }
        }
        return false;
    }

    // 提亮颜色方法
    private int lightenColor(int color, float factor) {
        int red = (int) ((Color.red(color) * (1 - factor) + 255 * factor));
        int green = (int) ((Color.green(color) * (1 - factor) + 255 * factor));
        int blue = (int) ((Color.blue(color) * (1 - factor) + 255 * factor));
        return Color.rgb(red, green, blue);
    }
}

统一设置圆饼图样式PieChartManager

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.SpannableString;
import android.view.View;

import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.PercentFormatter;
import com.limestone.auspicious.R;
import com.limestone.auspicious.XRJYApplication;

import java.util.List;

/**
 * Created by xiaomi on 2018/7/23.
 * 圆饼图管理类
 */
public class PieChartManager {

    private PieChart pieChart;
    private SpannableString CenterText;
    private Context mContext;
    public PieChartManager(PieChart pieChart, Context context, SpannableString CenterText) {
        this.pieChart = pieChart;
        this.CenterText=CenterText;
        this.mContext=context;
        initPieChart();
    }

    //初始化
    private void initPieChart() {
        //  是否显示中间的洞
        pieChart.setDrawHoleEnabled(false);
        pieChart.setHoleRadius(40f);//设置中间洞的大小
        pieChart.setHoleColor(mContext.getResources().getColor(R.color.transparent));

//        // 半透明圈
//        pieChart.setTransparentCircleRadius(30f);
//        pieChart.setTransparentCircleColor(Color.WHITE); //设置半透明圆圈的颜色
//        pieChart.setTransparentCircleAlpha(125); //设置半透明圆圈的透明度

//        //饼状图中间可以添加文字
//        pieChart.setDrawCenterText(false);
//        pieChart.setCenterText(CenterText); //设置中间文字
//        pieChart.setCenterTextColor(Color.parseColor("#71fcf9")); //中间问题的颜色
//        pieChart.setCenterTextSizePixels(36);  //中间文字的大小px
////        pieChart.setCenterTextRadiusPercent(10f);//设置中心文本的边界框的矩形半径,以饼图孔的默认值1.f(100%)的百分比表示。
//        pieChart.setCenterTextTypeface(Typeface.DEFAULT); //中间文字的样式
//        pieChart.setCenterTextOffset(0, 0); //中间文字的偏移量
        pieChart.setNoDataText("暂无数据");//设置饼图没有数据时显示的文本

        pieChart.setRotationAngle(0);// 初始旋转角度
        pieChart.setRotationEnabled(true);// 可以手动旋转
        pieChart.setUsePercentValues(true);//显示成百分比
        pieChart.getDescription().setEnabled(false); //取消右下角描述
        pieChart.setHighlightPerTapEnabled(true);//Boolean类型 设置点击Item高亮是否可用


        //是否显示每个部分的文字描述
        pieChart.setDrawEntryLabels(false);
        pieChart.setEntryLabelColor(mContext.getResources().getColor(R.color.black)); //描述文字的颜色
        pieChart.setEntryLabelTextSize(10);//描述文字的大小
        pieChart.setEntryLabelTypeface(Typeface.DEFAULT_BOLD); //描述文字的样式

        //图相对于上下左右的偏移
        pieChart.setExtraOffsets(10, 10, 10, 10);
        //图标的背景色
        pieChart.setBackgroundColor(Color.TRANSPARENT);
//        设置pieChart图表转动阻力摩擦系数[0,1]
        pieChart.setDragDecelerationFrictionCoef(0.75f);

        //设置饼图动画
        pieChart.animateY(1400, Easing.EaseInOutQuad);

        //获取图例
        Legend legend = pieChart.getLegend();
        legend.setEnabled(false);//Boolean类型   设置是否启用图列
        legend.setOrientation(Legend.LegendOrientation.VERTICAL);  //设置图例水平显示
        legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP); //顶部
        legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT); //右对其

        legend.setXEntrySpace(7f);//x轴的间距
        legend.setYEntrySpace(10f); //y轴的间距
        legend.setYOffset(10f);  //图例的y偏移量
        legend.setXOffset(10f);  //图例x的偏移量
        legend.setTextColor(Color.parseColor("#a1a1a1")); //图例文字的颜色
        legend.setTextSize(13);  //图例文字的大小

    }


    /**
     * 显示实心圆
     * @param yvals
     * @param colors
     */
    public void showSolidPieChart(List<PieEntry> yvals, List<Integer> colors) {
        //数据集合
        PieDataSet dataset = new PieDataSet(yvals, "");
        //填充每个区域的颜色
        dataset.setColors(colors);
        //是否在图上显示数值
        dataset.setDrawValues(true);
//        文字的大小
        dataset.setValueTextSize(14);
//        文字的颜色
        dataset.setValueTextColor(mContext.getResources().getColor(R.color.black));
//        文字的样式
        dataset.setValueTypeface(Typeface.DEFAULT_BOLD);

//      当值位置为外边线时,表示线的前半段长度。
        dataset.setValueLinePart1Length(0.4f);
//      当值位置为外边线时,表示线的后半段长度。
        dataset.setValueLinePart2Length(0.4f);
//      当ValuePosits为OutsiDice时,指示偏移为切片大小的百分比
        dataset.setValueLinePart1OffsetPercentage(80f);
        // 当值位置为外边线时,表示线的颜色。
        dataset.setValueLineColor(Color.parseColor("#61d2d2"));
//        设置Y值的位置是在圆内还是圆外
        dataset.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
        dataset.setValueLineVariableLength(true);
        //        设置X值的位置是在圆内还是圆外
        dataset.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
//        设置Y轴描述线和填充区域的颜色一致
//        dataset.setUsingSliceColorAsValueLineColor(false);
//        设置每条之前的间隙
        dataset.setSliceSpace(0);

        //设置饼状Item被选中时变化的距离
        dataset.setSelectionShift(5f);
        //填充数据
        PieData pieData = new PieData(dataset);
//        格式化显示的数据为%百分比
        pieData.setValueFormatter(new PercentFormatter());
//        显示试图
        pieChart.setData(pieData);
    }


    /**
     * 显示圆环
     * @param yVals
     * @param colors
     */
    public void  showRingPieChart(List<PieEntry> yVals, List<Integer> colors,String centerName){

        // 设置图层类型为软件模式,以支持阴影绘制
        pieChart.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        //显示为圆环
        pieChart.setDrawHoleEnabled(true);// 绘制空洞
        pieChart.setHoleRadius(70f);//设置中间洞的大小
        pieChart.setHoleColor(Color.parseColor("#FFFFFF")); // 空洞颜色为灰色
//        // 半透明圈
        pieChart.setTransparentCircleRadius(0);// 空洞半径为 0(不绘制透明圆)
//        pieChart.setTransparentCircleColor(Color.WHITE); //设置半透明圆圈的颜色
//        pieChart.setTransparentCircleAlpha(125); //设置半透明圆圈的透明度

        pieChart.setDrawCenterText(true);
        pieChart.setCenterTextSize(14f);
        pieChart.setCenterText(centerName);
        pieChart.setCenterTextTypeface(Typeface.DEFAULT_BOLD);
        pieChart.setCenterTextColor(XRJYApplication.getApplication().getResources().getColor(R.color.black));

        pieChart.setHighlightPerTapEnabled(true);//Boolean类型 设置点击Item高亮是否可用
        //数据集合
        PieDataSet dataset = new PieDataSet(yVals, "");
        //填充每个区域的颜色
        dataset.setColors(colors);
        // 增加每个扇形的透明边缘颜色
//        dataset.setSelectionShift(5f); // 设置选中时的移动距离,模拟立体感
//        dataset.setSliceSpace(3f); // 设置扇形之间的间距,增加分隔感
        // 遍历每个扇形,设置阴影效果
//        for (int i = 0; i < yVals.size(); i++) {
//            // 获取当前扇形的颜色
//            int pieColor = dataset.getColors().get(i);
//
//            // 计算基于当前颜色的阴影颜色 (通过降低透明度或变亮)
//            int shadowColor = ColorUtils.setAlphaComponent(pieColor, 150); // 将透明度降低,150 是半透明
//            int lighterShadowColor = lightenColor(pieColor, 0.5f); // 提亮原颜色
//            // 设置当前扇形的 Paint
//            Paint paint = pieChart.getRenderer().getPaintRender();
//            paint.setShadowLayer(30f, 0f, 0f, lighterShadowColor); // 使用提亮后的颜色设置发光效果
//
//            Paint paint2 = pieChart.getRenderer().getPaintHighlight();
//            paint2.setShadowLayer(30f, 0f, 0f, lighterShadowColor); // 使用提亮后的颜色设置发光效果
//        }

        //是否在图上显示数值
        dataset.setDrawValues(false);
//        文字的大小
        dataset.setValueTextSize(10);
//        文字的颜色
        dataset.setValueTextColor(mContext.getResources().getColor(R.color.black));
//        文字的样式
        dataset.setValueTypeface(Typeface.DEFAULT_BOLD);

//      当值位置为外边线时,表示线的前半段长度。
        dataset.setValueLinePart1Length(0.4f);
//      当值位置为外边线时,表示线的后半段长度。
        dataset.setValueLinePart2Length(0.8f);
//      当ValuePosits为OutsiDice时,指示偏移为切片大小的百分比
        dataset.setValueLinePart1OffsetPercentage(80f);
        // 当值位置为外边线时,表示线的颜色。
        dataset.setValueLineColor(Color.parseColor("#61d2d2"));
//        设置Y值的位置是在圆内还是圆外
        dataset.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);

        dataset.setValueLineVariableLength(true);
        //        设置X值的位置是在圆内还是圆外
        dataset.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
//        设置Y轴描述线和填充区域的颜色一致
//        dataset.setUsingSliceColorAsValueLineColor(false);
//        设置每条之前的间隙
        dataset.setSliceSpace(0);

        //设置饼状Item被选中时变化的距离
        dataset.setSelectionShift(5f);
        //填充数据
        PieData pieData = new PieData(dataset);
//        格式化显示的数据为%百分比
        pieData.setValueFormatter(new PercentFormatter());
//        显示试图
        pieChart.setData(pieData);
    }
    //此方法用于提亮颜色,模拟发散效果:
    private int lightenColor(int color, float factor) {
        int red = (int) ((Color.red(color) * (1 - factor) + 255 * factor));
        int green = (int) ((Color.green(color) * (1 - factor) + 255 * factor));
        int blue = (int) ((Color.blue(color) * (1 - factor) + 255 * factor));
        return Color.rgb(red, green, blue);
    }

}

使用方式

	//初始化
 	private List<PieEntry> yVals1 = new ArrayList<>();
    private List<PieEntry> yVals2 = new ArrayList<>();
    private List<Integer> colors = new ArrayList<>();
    private PieChartManager pieChartManager1;
    private PieChartManager pieChartManager2;
		//初始化
binding.layoutPositionRatio.chart1.setTouchEnabled(false);
binding.layoutPositionRatio.chart2.setTouchEnabled(false);
binding.layoutPositionRatio.chart1.setNoDataText("暂无数据");
binding.layoutPositionRatio.chart2.setNoDataText("暂无数据");
binding.layoutPositionRatio.chart1.setRenderer(new CustomPieChartRenderer(binding.layoutPositionRatio.chart1, binding.layoutPositionRatio.chart1.getAnimator(), binding.layoutPositionRatio.chart1.getViewPortHandler()));
binding.layoutPositionRatio.chart2.setRenderer(new CustomPieChartRenderer(binding.layoutPositionRatio.chart2, binding.layoutPositionRatio.chart2.getAnimator(), binding.layoutPositionRatio.chart2.getViewPortHandler()));
pieChartManager1 = new PieChartManager(binding.layoutPositionRatio.chart1, mContext, generateCenterSpannableText());
pieChartManager2 = new PieChartManager(binding.layoutPositionRatio.chart2, mContext, generateCenterSpannableText());
yVals2.add(pieEntry3);
yVals2.add(pieEntry4);
colors.add(ContextCompat.getColor(mContext, R.color.color_1BBE8A));
colors.add(ContextCompat.getColor(mContext, R.color.color_F14A4B));
pieChartManager1.showRingPieChart(yVals1, colors, cnSymbol1);
pieChartManager2.showRingPieChart(yVals2, colors, cnSymbol2);
// 默认高亮第一个扇形
binding.layoutPositionRatio.chart1.highlightValue(0, 0);
binding.layoutPositionRatio.chart2.highlightValue(0, 0);
binding.layoutPositionRatio.chart1.invalidate();
binding.layoutPositionRatio.chart2.invalidate();
private SpannableString generateCenterSpannableText() {
        SpannableString s = new SpannableString("MPAndroidChart\ndeveloped by Philipp Jahoda");
        s.setSpan(new RelativeSizeSpan(1.7f), 0, 14, 0);
        s.setSpan(new StyleSpan(Typeface.NORMAL), 14, s.length() - 15, 0);
        s.setSpan(new ForegroundColorSpan(Color.GRAY), 14, s.length() - 15, 0);
        s.setSpan(new RelativeSizeSpan(.8f), 14, s.length() - 15, 0);
        s.setSpan(new StyleSpan(Typeface.ITALIC), s.length() - 14, s.length(), 0);
        s.setSpan(new ForegroundColorSpan(ColorTemplate.getHoloBlue()), s.length() - 14, s.length(), 0);
        return s;
 }
		<LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <com.github.mikephil.charting.charts.PieChart
                android:id="@+id/chart1"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="@dimen/dp_150"
                />
            <com.github.mikephil.charting.charts.PieChart
                android:id="@+id/chart2"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="@dimen/dp_150"
                />
		</LinearLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值