canvas教程

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

字号+ 作者:H5之家 来源:H5之家 2017-12-08 17:12 我要评论( )

今天来做一做自定义的圆形统计图表,其实这个老早就做好了,只是今天项目不赶,我就把这个发出来。 先看效果图: 效果图 思路篇: 其实这个仔细想想,就是利用多个颜色不同的圆弧组合起来的一个圆, 所以,我们调用的时候,应该就是传入一个List,类里面就是

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


效果图

思路篇:

其实这个仔细想想,就是利用多个颜色不同的圆弧组合起来的一个圆,
所以,我们调用的时候,应该就是传入一个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) }

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

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML5 Canvas自定义圆角矩形与虚线(Rounded Rectangle and Dash Line)

    HTML5 Canvas自定义圆角矩形与虚线(Rounded Rectangle and Dash Line

    2017-11-20 14:14

  • Android中自定义View(4)

    Android中自定义View(4)

    2017-11-13 14:03

  • 如何通过HTMl5 Canvas实现圆形进度条并显示数字百分比效果?

    如何通过HTMl5 Canvas实现圆形进度条并显示数字百分比效果?

    2017-11-11 14:01

  • 使用html5 canvas绘制圆形或弧线

    使用html5 canvas绘制圆形或弧线

    2017-11-10 17:06

网友点评