持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第十三天,点击查看活动详情
Android自定义View系列---蜘蛛网六维图小实战(Kotlin)
前言
源代码github 我们学习了前面的绘制基础,我们来通过实现一个蜘蛛网六维图来巩固一下之前的知识
实战讲解
思路步骤
- 绘制蜘蛛网格
- 绘制网格中线
- 绘制数据
前期准备
这是一个自定义View,所以你需要继承一下View,并且把基本的属性都初始化
package com.customize.study.chapter_1
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import java.lang.Math.sin
class SpiderView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
//蛛网和中线的画笔
private var radarPaint: Paint = Paint()
//数据的画笔
private var valuePaint: Paint = Paint()
init {
//设置描边
radarPaint.style = Paint.Style.STROKE
//设置绿色
radarPaint.color = Color.GREEN
//设置抗锯齿
radarPaint.isAntiAlias = true
//设置画笔宽度
radarPaint.strokeWidth = 5f
valuePaint.style = Paint.Style.FILL
valuePaint.color = Color.BLUE
valuePaint.isAntiAlias = true
valuePaint.strokeWidth = 5f
}
//半径
private var radius = 0f
//中心x
private var centerX = 0f
//中心y
private var centerY = 0f
//蜘蛛网的个数
private val count = 6
//每个顶点的的角度
private val angle = (Math.PI * 2f / count)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
//获取半径 width和height的最短的90%
radius = h.coerceAtMost(w) / 2 * 0.9f
//获取中心坐标
centerX = w / 2f
centerY = h / 2f
//刷新控件
postInvalidate()
super.onSizeChanged(w, h, oldw, oldh)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//绘制蜘蛛网格
drawPolygon(canvas)
//画网格中线
drawLine(canvas)
//画数据图
drawRegion(canvas)
}
}
我们在onDraw()中开始绘制我们的蜘蛛网,就三个方法对应之前的三个步骤,那我们开始一个方法开始讲解
drawPolygon(canvas)
private fdrawPolygon(canvas)un drawPolygon(canvas: Canvas) {
//创建path
val path = Path()
//每个网格距离中心点距离
val r = radius / count
for (index in 0..count) {
//当前网格的距离
val curR = r * index
//重置路径
path.reset()
for (j in 0..count) {
//判断是否第一个顶点
if (j == 0) {
path.moveTo(centerX + curR, centerY)
} else {
//其他顶点 具体请看下面的图
val x = centerX + curR * Math.cos((angle * j))
val y = centerY + curR * sin((angle * j))
//连成线
path.lineTo(x.toFloat(), y.toFloat())
}
}
//关闭一下
path.close()
//绘制出来
canvas.drawPath(path, radarPaint)
}
}
drawLine
private fun drawLine(canvas: Canvas) {
val path = Path()
for (index in 0..count) {
path.reset()
path.moveTo(centerX, centerY)
val x = centerX + radius * Math.cos((angle * index))
val y = centerY + radius * sin((angle * index))
path.lineTo(x.toFloat(), y.toFloat())
canvas.drawPath(path,radarPaint)
}
}
drawRegion
//显示的数据
private val data = doubleArrayOf(2.0, 5.0, 1.0, 6.0, 4.0, 5.0)
private fun drawRegion(canvas: Canvas) {
val path = Path()
//设置透明度
valuePaint.alpha = 127
for (i in 0 until count) {
val percent: Double = data.get(i) / 6
//计算数据在六维图的位置
val x = (centerX + radius * Math.cos(angle * i) * percent).toFloat()
val y = (centerY + radius * sin(angle * i) * percent).toFloat()
if (i == 0) {
path.moveTo(x, centerY)
} else {
path.lineTo(x, y)
}
//绘制小圆点
canvas.drawCircle(x, y, 10f, valuePaint)
}
//绘制填充区域
valuePaint.style = Paint.Style.FILL_AND_STROKE
canvas.drawPath(path, valuePaint)
}
总结
自定义绘制六维图的思路与代码就这么简单,都是使用基本属性