package com.example.customviewapplication
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import kotlin.random.Random
class CustomView1 @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
isAntiAlias = true
}
private val rectF = RectF()
private val path = Path()
private var colors = intArrayOf(
Color.RED, //51.75%
Color.GREEN, //36.98
Color.BLUE, // 4.72
Color.YELLOW, // 3.63
Color.WHITE // 2.92
)
private var ratio = floatArrayOf(
0.0f,
0.8873f,
0.9345f,
0.9708f,
1f
)
private var points: List<List<Point>>
private val mWidth: Int
private val mHeight: Int
private fun createPoints(ratios: List<Float>): List<List<Point>> {
val result = mutableListOf<List<Point>>()
val totalLength = (mWidth + mHeight) * 2
var totalPercent = 0f
var point = Point(0f, 0f)
ratios
.map { it / 100f }
.forEach { percent ->
val points = mutableListOf(Point(point.x, point.y))
totalPercent += totalLength * percent
val newX: Float
val newY: Float
when {
totalPercent > 2 * mWidth + mHeight -> {
if ((totalPercent - totalLength * percent) in (mWidth + mHeight)..(2 * mWidth + mHeight)) {
points += Point(0f, mHeight.toFloat())
}
newY = (totalPercent - (2 * mWidth + mHeight))
points += Point(0f, newY)
result += points
point = point.copy(x = 0f, y = newY)
}
totalPercent > mWidth + mHeight -> {
if ((totalPercent - totalLength * percent) <= mWidth + mHeight) {
points += Point(mWidth.toFloat(), 0f)
points += Point(mWidth.toFloat(), mHeight.toFloat())
}
newX = mWidth - (totalPercent - (mWidth + mHeight))
points += Point(newX, mHeight.toFloat())
result += points
point = point.copy(x = newX, y = mHeight.toFloat())
}
totalPercent > mWidth -> {
newY = totalPercent - mWidth
points += Point(0f, newY)
result += points
point = point.copy(x = 0f, y = newY)
}
else -> {
newX = totalPercent
points += Point(newX, 0f)
result += points
point = point.copy(x = newX, y = 0f)
}
}
}
return result
}
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView1, defStyleAttr, 0)
typedArray.recycle()
mWidth = resources.getDimensionPixelSize(R.dimen.width)
mHeight = resources.getDimensionPixelSize(R.dimen.height)
points = createPoints(listOf(51.75f, 36.98f, 4.72f, 3.63f, 2.92f))
}
@SuppressWarnings("all")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
val width = measureDimension(desiredWidth, widthMeasureSpec)
val height = measureDimension(desiredHeight, heightMeasureSpec)
setMeasuredDimension(width, height)
points = createPoints(listOf(51.75f, 36.98f, 4.72f, 3.63f, 2.92f))
}
private fun measureDimension(desiredSize: Int, measureSpec: Int): Int {
var result: Int
val specMode = View.MeasureSpec.getMode(measureSpec)
val specSize = View.MeasureSpec.getSize(measureSpec)
if (specMode == View.MeasureSpec.EXACTLY) {
result = specSize
} else {
result = desiredSize
if (specMode == View.MeasureSpec.AT_MOST) {
result = Math.min(result, specSize)
}
}
return result
}
override fun onDraw(canvas: Canvas?) {
canvas ?: return
val centerPointX = width / 2f
val centerPointY = height / 2f
points.forEach { embeddedPoints ->
path.moveTo(centerPointX, centerPointY)
embeddedPoints.forEach {
path.lineTo(it.x, it.y)
}
path.lineTo(centerPointX, centerPointY)
paint.shader = createShaderForSector()
canvas.drawPath(path, paint)
path.reset()
}
super.onDraw(canvas)
}
private fun createShader(colors: IntArray, ratio: FloatArray) =
SweepGradient(
width / 2f,
height / 2f,
colors,
ratio
)
private fun createShaderForCubic() =
LinearGradient(
width / 5f,
height.toFloat(),
width / 2f,
height / 2f,
Color.TRANSPARENT,
Color.argb(255, Random.nextInt(256), Random.nextInt(256), Random.nextInt(256)),
Shader.TileMode.MIRROR
)
private fun createShaderForSector() =
LinearGradient(
0f,
height.toFloat(),
width / 2f,
height / 2f,
Color.TRANSPARENT,
Color.argb(255, Random.nextInt(256), Random.nextInt(256), Random.nextInt(256)),
Shader.TileMode.MIRROR
)
private fun createRadialShaderForSector() =
SweepGradient(
width / 2f,
height /2f,
Color.TRANSPARENT,
Color.argb(255, Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))
)
private fun createShaderForQuad() =
LinearGradient(
width / 2f,
height.toFloat(),
width * 3f / 4f,
height / 2f,
Color.TRANSPARENT,
Color.WHITE,
Shader.TileMode.MIRROR
)
private fun createShaderForAnalysis() =
LinearGradient(
0f,
height * 5f / 6f,
width / 2f,
height / 2f,
Color.TRANSPARENT,
Color.WHITE,
Shader.TileMode.MIRROR
)
private data class Point(val x: Float, val y: Float)
}