小牛试刀,花了一个小时写了个网状图,如下
绘制的思路分成三部
1,首先绘制三条连接的长的直线,代码如下
//画第一条竖线
canvas.drawLine(0f, -r, 0f, r, mPaintLineBg)
val averageAngle = 360f / PART
val y = (Math.sin(averageAngle / 2 / 180 * Math.PI) * r).toFloat()
val x = (Math.cos(averageAngle / 2 / 180 * Math.PI) * r).toFloat()
//斜线1
canvas.drawLine(-x, y, x, -y, mPaintLineBg)
//斜线2
canvas.drawLine(-x, -y, x, y, mPaintLineBg)
2,然后绘制四个正六边形
for (i in 1..4) {
val xx = x * i / 4
val yy = y * i / 4
val rr = r * i / 4
val path = Path()
path.moveTo(0f, rr)
path.lineTo(xx, yy)
path.lineTo(xx, -yy)
path.lineTo(0f, -rr)
path.lineTo(-xx, -yy)
path.lineTo(-xx, yy)
path.close()
canvas.drawPath(path, mPaintLineBg)
}
最后绘制区域图形
val path = Path()
if (topRaw == 0f) {
path.moveTo(0f, 0f)
} else {
path.moveTo(0f, -r * topRaw)
canvas.drawCircle(0f, -r * topRaw, circleRaduis, mPaintCirlce)
}
if (topRightRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y2 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * topRightRaw)).toFloat()
val x2 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * topRightRaw)).toFloat()
path.lineTo(x2, -y2)
canvas.drawCircle(x2, -y2, circleRaduis, mPaintCirlce)
}
if (bottomRightRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y3 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * bottomRightRaw)).toFloat()
val x3 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * bottomRightRaw)).toFloat()
path.lineTo(x3, y3)
canvas.drawCircle(x3, y3, circleRaduis, mPaintCirlce)
}
if (bottomRaw == 0f) {
path.moveTo(0f, 0f)
} else {
path.lineTo(0f, r * bottomRaw)
canvas.drawCircle(0f, r * bottomRaw, circleRaduis, mPaintCirlce)
}
if (bottomLeftRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y4 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * bottomLeftRaw)).toFloat()
val x4 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * bottomLeftRaw)).toFloat()
path.lineTo(-x4, y4)
canvas.drawCircle(-x4, y4, circleRaduis, mPaintCirlce)
}
if (topLeftRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y5 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * topLeftRaw)).toFloat()
val x5 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * topLeftRaw)).toFloat()
path.lineTo(-x5, -y5)
canvas.drawCircle(-x5, -y5, circleRaduis, mPaintCirlce)
}
path.close()
canvas.drawPath(path, mPaintLine)
最后贴上所有代码
class SpiderView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
companion object {
val PART = 6
}
//画背景的
private val mPaintLineBg = Paint(Paint.ANTI_ALIAS_FLAG)
//画区域
private val mPaintLine = Paint(Paint.ANTI_ALIAS_FLAG)
//
private val mPaintCirlce = Paint(Paint.ANTI_ALIAS_FLAG)
// 宽高
private var mWidth: Int = 0
private var mHeight: Int = 0
//中心的坐标
private var mCenterX: Int = 0
private var mCenterY: Int = 0
//总进度
private var count: Int = 100
private var topRaw: Float = 0f
private var topRightRaw: Float = 0f
private var bottomRightRaw: Float = 0f
private var bottomRaw: Float = 0f
private var bottomLeftRaw: Float = 0f
private var topLeftRaw: Float = 0f
private val circleRaduis: Float = dp2px(3f)
init {
mPaintLineBg.color = Color.parseColor("#0000EE")
mPaintLineBg.style = Paint.Style.STROKE
mPaintLineBg.strokeWidth = dp2px(0.5f)
mPaintLine.style = Paint.Style.FILL
mPaintLine.color = Color.parseColor("#aaB22222")
mPaintCirlce.style = Paint.Style.FILL
mPaintCirlce.color = Color.parseColor("#0000EE")
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = measureWidth(widthMeasureSpec)
val height = measureHeight(heightMeasureSpec)
val imageSize = if (width < height) width else height
setMeasuredDimension(imageSize, imageSize)
}
/**
* 测量宽度
*/
private fun measureWidth(measureSpec: Int): Int {
val result: Int
val specMode = View.MeasureSpec.getMode(measureSpec)
val specSize = View.MeasureSpec.getSize(measureSpec)
if (specMode == View.MeasureSpec.EXACTLY) {
result = specSize
} else if (specMode == View.MeasureSpec.AT_MOST) {
result = specSize
} else {
result = specSize
}
return result
}
/**
* 测量高度
*/
private fun measureHeight(measureSpecHeight: Int): Int {
val result: Int
val specMode = View.MeasureSpec.getMode(measureSpecHeight)
val specSize = View.MeasureSpec.getSize(measureSpecHeight)
if (specMode == View.MeasureSpec.EXACTLY) {
result = specSize
} else if (specMode == View.MeasureSpec.AT_MOST) {
result = specSize
} else {
result = specSize
}
return result
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mWidth = w;
mHeight = h;
mCenterX = mWidth / 2
mCenterY = mHeight / 2
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.translate(mCenterX.toFloat(), mCenterY.toFloat())
val r = Math.min(mCenterX, mCenterY).toFloat()
//画第一条竖线
canvas.drawLine(0f, -r, 0f, r, mPaintLineBg)
val averageAngle = 360f / PART
val y = (Math.sin(averageAngle / 2 / 180 * Math.PI) * r).toFloat()
val x = (Math.cos(averageAngle / 2 / 180 * Math.PI) * r).toFloat()
//斜线1
canvas.drawLine(-x, y, x, -y, mPaintLineBg)
//斜线2
canvas.drawLine(-x, -y, x, y, mPaintLineBg)
for (i in 1..4) {
val xx = x * i / 4
val yy = y * i / 4
val rr = r * i / 4
val path = Path()
path.moveTo(0f, rr)
path.lineTo(xx, yy)
path.lineTo(xx, -yy)
path.lineTo(0f, -rr)
path.lineTo(-xx, -yy)
path.lineTo(-xx, yy)
path.close()
canvas.drawPath(path, mPaintLineBg)
}
val path = Path()
if (topRaw == 0f) {
path.moveTo(0f, 0f)
} else {
path.moveTo(0f, -r * topRaw)
canvas.drawCircle(0f, -r * topRaw, circleRaduis, mPaintCirlce)
}
if (topRightRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y2 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * topRightRaw)).toFloat()
val x2 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * topRightRaw)).toFloat()
path.lineTo(x2, -y2)
canvas.drawCircle(x2, -y2, circleRaduis, mPaintCirlce)
}
if (bottomRightRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y3 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * bottomRightRaw)).toFloat()
val x3 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * bottomRightRaw)).toFloat()
path.lineTo(x3, y3)
canvas.drawCircle(x3, y3, circleRaduis, mPaintCirlce)
}
if (bottomRaw == 0f) {
path.moveTo(0f, 0f)
} else {
path.lineTo(0f, r * bottomRaw)
canvas.drawCircle(0f, r * bottomRaw, circleRaduis, mPaintCirlce)
}
if (bottomLeftRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y4 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * bottomLeftRaw)).toFloat()
val x4 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * bottomLeftRaw)).toFloat()
path.lineTo(-x4, y4)
canvas.drawCircle(-x4, y4, circleRaduis, mPaintCirlce)
}
if (topLeftRaw == 0f) {
path.lineTo(0f, 0f)
} else {
val y5 = (Math.sin(averageAngle / 2 / 180 * Math.PI) * (r * topLeftRaw)).toFloat()
val x5 = (Math.cos(averageAngle / 2 / 180 * Math.PI) * (r * topLeftRaw)).toFloat()
path.lineTo(-x5, -y5)
canvas.drawCircle(-x5, -y5, circleRaduis, mPaintCirlce)
}
path.close()
canvas.drawPath(path, mPaintLine)
}
private fun sp2px(spValue: Float): Float {
val fontScale = resources.displayMetrics.scaledDensity
return (spValue * fontScale + 0.5f)
}
private fun dp2px(dp: Float): Float {
val scale = resources.displayMetrics.density
return (dp * scale + 0.5f)
}
public fun setProgress(top: Int, topRight: Int, bottomRight: Int, bottom: Int, bottomLeft: Int, topLeft: Int) {
topRaw = (top * 1f / count)
bottomRightRaw = (bottomRight * 1f / count)
bottomRaw = (bottom * 1f / count)
bottomLeftRaw = (bottomLeft * 1f / count)
topLeftRaw = (topLeft * 1f / count)
topRightRaw = (topRight * 1f / count)
invalidate()
}
public fun setCount(count: Int) {
this.count = count
}
}