自定义View——环形统计图

自定义View
当Android系统内置的View无法实现我们的需求时,自定义View可以很好的解决我们的问题,例如现在想做出一个动态的环形统计图效果,只靠系统内置VIew是无法完成的。写一个自定义View类,首先要让它继承自View,然后重写两个函数,onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw()负责把当前这个View绘制出来,当然还必须写上构造函数

public class RingChart extends View {

    public RingChart(Context context) {
        super(context);
    }

    public RingChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

在activity的oncreate方法中创建并实例化这个自定义View,并添加到frameLayout帧布局中,这样就可以在活动中显示

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FrameLayout frameLayout = (FrameLayout) findViewById(R.id.layout);
        frameLayout.addView(new RingChart(this));

    }
}

模仿账单的统计图
绘制成圆环统计效果,我们可以使用drawArc实现,为每一段数据画一段扇形,最后用一个白色的更小的圆遮盖住扇形的中间一部分,这样就会有圆环的效果了,看一下最后的效果图:
在这里插入图片描述

/**
     * drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
     * drawArc() 是使用一个椭圆来描述弧形的。
     * left, top, right, bottom 描述的是这个弧形所在的椭圆;
     * startAngle 是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度),
     * sweepAngle 是弧形划过的角度;
     * useCenter 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。
     */

那么我们的扇形数据类就需要以下几个属性

	private String text; //标签文本
    private float value; //各标签数值
    private float Angle; //需要绘制的圆弧角度
    private float CurrentStartAngle; //当前起始角度
    private float Percentage; //百分比
    private int color; //各部分颜色

扇形的每一段颜色通过先定义好的一个颜色数组去得到,当获得数据列表时,根据数据的条数去设置每一段扇形的颜色,这里先放了8个颜色,即数据列表中最多可以有八条,颜色列表可根据需要具体更改

public final static int[] COLORS = {
        Color.parseColor("#FFD778"), Color.parseColor("#FEA3C2"),
        Color.parseColor("#66DAD9"),Color.parseColor("#9092FF"),
        Color.parseColor("#A0E491"),Color.parseColor("#6BD9AC"),
        Color.parseColor("#75A2FF"),Color.parseColor("#6BD9AC")
};

虽然ViewData类中设置了很多属性,但我们真正传入的只有text和value,即标签和数据,其他的像总和、百分比、角度都可以通过计算得到,所以在绘制扇形之前还需要对数据进行以下处理

	//初始化数据
    private void initData(List<ViewData> mData){
        if (mData == null || mData.size() == 0) {
            return;
        }

        //根据数据条数确定颜色
        for (int i = 0; i < mData.size(); i++) {
            ViewData data = mData.get(i);
            sumValue += data.getValue();
            data.setColor(COLORS[i]);
        }

        //计算百分比和角度
        float currentStartAngle = 0f; //设置起始角度为0
        for (int i = 0; i < mData.size(); i++) {
            ViewData data = mData.get(i);
            //为每一段设置起始角度
            data.setCurrentStartAngle(currentStartAngle);
            //通过总和来计算百分比
            float percentage = data.getValue() / sumValue;
            //通过百分比来计算对应的角度
            float angle = percentage * 360;
            //设置数据
            data.setPercentage(percentage);
            data.setAngle(angle);
            currentStartAngle += angle;
        }
    }

拿到数据之后我们就可以绘制扇形了,通过循环,为数据列表的每一个数据都绘制一段扇形,最终是一个圆形的样子

	for (int i= 0; i < viewDataList.size(); i++){
            ViewData data = viewDataList.get(i);
            //设置画笔颜色
            mPaint.setColor(data.getColor());
            //绘制扇形
            canvas.drawArc(left,top,right,bottom,data.getCurrentStartAngle(),data.getAngle(),true,mPaint);
    } 

绘制一个更小的圆遮挡,并在中间写上文字

	//绘制一个更小的圆将扇形遮挡中间的部分,让效果看起来变成一个圆环
   	 mPaint.setColor(Color.WHITE);
     canvas.drawCircle(centerX,centerY, (float) (r/1.4),mPaint);
     mPaint.setColor(Color.BLACK);
     float width = mPaint.measureText(sumValue+"元",0,(sumValue+"元").length());
     canvas.drawText(sumValue+"元",centerX - width/2,centerY+10,mPaint);

这样一个环形统计图的样子就出来了,再定义一个动画让它有动态效果,动画时间设了2秒,2秒之后动画加载完会显示默认显示效果

    public class RingChartAnimation extends Animation{
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 2.0f) {
                for (int i = 0; i < viewDataList.size(); i++) {
                    ViewData data = viewDataList.get(i);
                    //通过总和来计算百分比
                    float percentage = data.getValue() / sumValue;
                    //通过百分比来计算对应的角度
                    float angle = percentage * 360;
                    //根据插入时间来计算角度
                    angle = angle * interpolatedTime;
                    data.setAngle(angle);
                }
            } else {//默认显示效果
                for (int i = 0; i < viewDataList.size(); i++) {
                    //通过总和来计算百分比
                    ViewData data = viewDataList.get(i);
                    float percentage = data.getValue() / sumValue;
                    //通过百分比来计算对应的角度
                    float angle = percentage * 360;
                    data.setPercentage(percentage);
                    data.setAngle(angle);
                }
            }
            invalidate();
        }
    }

对于如何设置圆环上文本标签的位置,这里学习了 自定义View之扇形统计图,写的非常详细,完全解决了我的困扰

那我们在写完所有绘制过程之后,就可以在MainActivity中传数据了,方便起见,这里就直接定义一个数据列表传入了,运行之后就是我们的最后效果图了

public class MainActivity extends AppCompatActivity {

    RingChart ringChart;
    List<ViewData> viewDataList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FrameLayout frameLayout = (FrameLayout) findViewById(R.id.layout);
        ringChart = new RingChart(this);
        frameLayout.addView(ringChart);
        
        initData();
        ringChart.setData(viewDataList);
    }

    public void initData(){
        viewDataList.add(new ViewData("饮食",800));
        viewDataList.add(new ViewData("出行",300));
        viewDataList.add(new ViewData("购物",500));
        viewDataList.add(new ViewData("娱乐",200));
        viewDataList.add(new ViewData("住房",200));
        viewDataList.add(new ViewData("其他",100));
    }
}

在这里插入图片描述

通过这个例子可以看出自定义View的可扩展性还是很强大的,复杂图形j经过拆分、组合、加上动画效果,会让普通的界面有更好的观感

完整代码已上传Github

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自定义控件是Android开发中常见的任务之一。下面是一步一步教你如何自定义控件的简要指南: 第一步:创建一个新的Java类作为你的自定义控件。 首先,创建一个新的Java类,可以命名为你想要的控件名称。这个类应该继承自Android框架中的现有控件,例如View、TextView等。例如,如果你想要创建一个自定义按钮,可以创建一个名为CustomButton的类,并让它继承自Button类。 第二步:实现构造函数和属性。 在你的自定义控件类中,你可以实现构造函数和属性,以便对控件进行初始化和设置。你可以定义自己的属性,例如颜色、大小等,以及相应的getter和setter方法。 第三步:重写绘制方法。 要自定义控件的外观,你需要重写它的绘制方法。最常用的方法是重写`onDraw()`方法,在其中使用Canvas绘制你想要的形状、文本等。 第四步:处理用户交互。 如果你的自定义控件需要与用户进行交互,你可以重写相应的触摸事件(例如`onTouchEvent()`)或点击事件(例如`setOnClickListener()`)来处理用户操作。 第五步:在布局文件中使用自定义控件。 完成以上步骤后,你可以在布局文件中使用你的自定义控件了。只需在布局文件中添加一个与你的控件类名相对应的XML标签,并设置相应的属性。 这只是一个简要的指南,帮助你开始自定义控件的过程。在实际开发中,你可能需要更多的步骤和细节来完成你的自定义控件。你可以参考Android官方文档或其他教程来获取更多信息和示例代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值