美文网首页UIAndroid开发经验谈Android开发
自定义控件之圆形统计图表

自定义控件之圆形统计图表

作者: xiaolei123 | 来源:发表于2017-12-04 11:41 被阅读146次

    今天来做一做自定义的圆形统计图表,其实这个老早就做好了,只是今天项目不赶,我就把这个发出来。
    先看效果图:


    效果图

    思路篇:

    其实这个仔细想想,就是利用多个颜色不同的圆弧组合起来的一个圆,
    所以,我们调用的时候,应该就是传入一个List,类里面就是值,和相应的颜色:

    class Element(@ColorInt val color: Int, val progress: Float)
    

    我们这里自定义一个类,构造参数,第一个为颜色,第二个则为对应的值,

    我们在用canvas画的时候,会去遍历这个List,然后算出总值,再去自动算出当前的比例,在用当前element的颜色去画出来,关键代码如下:

    override fun onDraw(canvas: Canvas?)
    {
            var angle = startAngle//起始画的角度
            paint.strokeWidth = strokeWidth;//画笔的宽度
            var allValue = 0f//list里所有值得总数
            multiElement.all { entry -> //这里把所有遍历,拿到总数
                allValue += entry.value
                true
            }
            for (entry in multiElement)
            {
                val sweepAngle = (entry.value.toFloat() / allValue) * 360//这里算出当前值除以总和,再乘以360度,得出本次item所占的角度
                paint.color = entry.key//设置颜色
                canvas?.drawArc(rectf, angle, sweepAngle, false, paint)//开始画
                angle += sweepAngle//下一个画的开始,则是这次的结尾,因为需要衔接起来画一个圆
            }
            super.onDraw(canvas)
    }
    

    这里有一个需要注意的地方,就是因为画出的是一个弧度,所以由于画笔的宽度,画出来的会有一半被控件宽度遮住,所以为了完整的显示效果,在计算画图的区域的时候,需要把画笔的宽度去掉计算进去,才能显示完整的效果。

    private val rectf by lazy {
            when
            {
                mWidth > mHeight  -> RectF(mWidth / 2 - mHeight / 2 + strokeWidth / 2, 0f + strokeWidth / 2, mWidth / 2 - mHeight / 2 + mHeight - strokeWidth / 2, mHeight - strokeWidth / 2)
                mWidth == mHeight -> RectF(0f + strokeWidth / 2, 0f + strokeWidth / 2, min(mWidth, mHeight) - strokeWidth / 2, min(mWidth, mHeight) - strokeWidth / 2)
                else              -> RectF(0f + strokeWidth / 2, mHeight / 2 - mWidth / 2 + strokeWidth / 2, mWidth - strokeWidth / 2, mHeight / 2 - mWidth / 2 + mWidth - strokeWidth / 2)
            }
        }
    

    这段代码展示的是,在宽高不同的情况,计算不同的区域,能显示在控件的最中间,并且把画笔宽度计算进去,能显示出完整的效果。

    代码篇

    这里贴出我的完整代码,其实就是一个类,只不过,因为是自定义View,保不齐下一次也用的上,所以这里做一个记录,github就不上传了,就一个kt文件,懒得搞了。

    package com.yongxing.HuYing.widgets
    
    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Color
    import android.graphics.Paint
    import android.graphics.RectF
    import android.support.annotation.ColorInt
    import android.support.v4.util.ArrayMap
    import android.util.AttributeSet
    import android.view.View
    import com.yongxing.HuYing.utils.DensityUtil
    import kotlin.math.min
    
    /**
     * Created by xiaolei on 2017/11/29.
     */
    
    class MultiElementProgress @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr)
    {
        private var strokeWidth = 20f //画笔宽度
        private var startAngle = -45f //开始角度
        private val paint by lazy {
            Paint().apply {
                isAntiAlias = true
                color = Color.RED
                style = Paint.Style.STROKE
                strokeWidth = this@MultiElementProgress.strokeWidth
            }
        }
        private val rectf by lazy {
            when
            {
                mWidth > mHeight  -> RectF(mWidth / 2 - mHeight / 2 + strokeWidth / 2, 0f + strokeWidth / 2, mWidth / 2 - mHeight / 2 + mHeight - strokeWidth / 2, mHeight - strokeWidth / 2)
                mWidth == mHeight -> RectF(0f + strokeWidth / 2, 0f + strokeWidth / 2, min(mWidth, mHeight) - strokeWidth / 2, min(mWidth, mHeight) - strokeWidth / 2)
                else              -> RectF(0f + strokeWidth / 2, mHeight / 2 - mWidth / 2 + strokeWidth / 2, mWidth - strokeWidth / 2, mHeight / 2 - mWidth / 2 + mWidth - strokeWidth / 2)
            }
        }
        private val multiElement by lazy { ArrayMap<Int, Float>() }
        private var mHeight: Float = 0f
        private var mWidth: Float = 0f
    
        init
        {
            multiElement.put(Color.parseColor("#eadc4b"), 50f)
            multiElement.put(Color.parseColor("#f9a844"), 50f)
            multiElement.put(Color.parseColor("#b5db39"), 50f)
            strokeWidth = DensityUtil.dip2px(context, 16f).toFloat()
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
        {
            mHeight = View.MeasureSpec.getSize(heightMeasureSpec).toFloat()
            mWidth = View.MeasureSpec.getSize(widthMeasureSpec).toFloat()
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    
        override fun onDraw(canvas: Canvas?)
        {
            var angle = startAngle
            paint.strokeWidth = strokeWidth;
            var allValue = 0f
            multiElement.all { entry ->
                allValue += entry.value
                true
            }
            for (entry in multiElement)
            {
                val sweepAngle = (entry.value.toFloat() / allValue) * 360
                paint.color = entry.key
                canvas?.drawArc(rectf, angle, sweepAngle, false, paint)
                angle += sweepAngle
            }
            super.onDraw(canvas)
        }
    
        /**
         * 设置每一个选项的 Item
         */
        public fun setProgress(elements: List<Element>)
        {
            multiElement.clear()
            for (element in elements)
            {
                multiElement.put(element.color, element.progress)
            }
            postInvalidate()
        }
    
        /**
         * 设置画笔宽度
         */
        public fun setStrokeWidth(strokeWidth: Float)
        {
            this.strokeWidth = strokeWidth
            postInvalidate()
        }
    
        /**
         * 设置开始画的角度
         */
        public fun setStartAngle(startAngle: Float)
        {
            this.startAngle = startAngle
            postInvalidate()
        }
    
    
        public class Element(@ColorInt val color: Int, val progress: Float)
    
    }
    
    

    要用的就自己拷贝拿走吧,根据自己的需求改吧改吧用用也行啊。 _##

    QQ群:559259945

    相关文章

      网友评论

      本文标题:自定义控件之圆形统计图表

      本文链接:https://www.haomeiwen.com/subject/shgtixtx.html