Created
June 2, 2023 05:56
-
-
Save Bloody-Badboy/4f9ff9d601ef0ce4cfaa41cae7f07856 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.arpan.ui.widget | |
import android.content.Context | |
import android.graphics.Canvas | |
import android.graphics.Color | |
import android.graphics.Paint | |
import android.graphics.RectF | |
import android.os.Parcel | |
import android.os.Parcelable | |
import android.util.AttributeSet | |
import android.view.View | |
import androidx.core.graphics.withTranslation | |
import kotlin.math.cos | |
import kotlin.math.max | |
import kotlin.math.min | |
import kotlin.math.sin | |
class SalesProgressView @JvmOverloads constructor( | |
context: Context, | |
attributeSet: AttributeSet? = null | |
) : View(context, attributeSet) { | |
private val rectF = RectF() | |
private val indicatorRectF = RectF() | |
private val strokeWidth = 2f.dp | |
private val indicatorSize = 12f.dp | |
private val indicatorStrokeWidth = 1f.dp | |
private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.FILL | |
color = Color.argb(0x66, 0xFF, 0xFF, 0xFF) | |
} | |
private val strokeBackgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.STROKE | |
strokeWidth = [email protected] | |
strokeCap = Paint.Cap.ROUND | |
color = Color.WHITE | |
} | |
private val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.STROKE | |
strokeWidth = [email protected] | |
strokeCap = Paint.Cap.ROUND | |
color = Color.rgb(0xFF, 0x75, 0x41) | |
} | |
private val indicatorFillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.FILL | |
color = Color.WHITE | |
} | |
private val indicatorStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { | |
style = Paint.Style.STROKE | |
strokeWidth = [email protected] | |
color = Color.rgb(0xFF, 0x75, 0x41) | |
} | |
var progress: Float = 0f | |
set(value) { | |
field = value.coerceAtMost(100f) | |
invalidate() | |
} | |
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { | |
val height = getDefaultSize(suggestedMinimumHeight, heightMeasureSpec) | |
val width = getDefaultSize(suggestedMinimumWidth, widthMeasureSpec) | |
val min = min(width, height) | |
setMeasuredDimension(min, min) | |
val halfStrokeWidth = strokeWidth / 2f | |
val halfIndicatorWidth = indicatorSize / 2f | |
val halfFinal = max(halfStrokeWidth, halfIndicatorWidth) | |
rectF.set( | |
halfFinal, | |
halfFinal, | |
min - halfFinal, | |
min - halfFinal | |
) | |
val halfIndicatorStrokeWidth = indicatorStrokeWidth / 2f | |
indicatorRectF.set( | |
-halfIndicatorWidth + halfIndicatorStrokeWidth, | |
-halfIndicatorWidth + halfIndicatorStrokeWidth, | |
halfIndicatorWidth - halfIndicatorStrokeWidth, | |
halfIndicatorWidth - halfIndicatorStrokeWidth | |
) | |
} | |
override fun onDraw(canvas: Canvas) { | |
super.onDraw(canvas) | |
val startAngle = -90f | |
val angle = 360 * progress / 100f | |
val radius = rectF.width() / 2f | |
canvas.drawOval(rectF, backgroundPaint) | |
canvas.drawOval(rectF, strokeBackgroundPaint) | |
canvas.drawArc(rectF, startAngle, angle, false, strokePaint) | |
val x = (radius * cos(Math.toRadians(angle + startAngle * 1.0)).toFloat()) + rectF.centerX() | |
val y = (radius * sin(Math.toRadians(angle + startAngle * 1.0)).toFloat()) + rectF.centerY() | |
canvas.withTranslation(x, y) { | |
canvas.drawOval(indicatorRectF, indicatorFillPaint) | |
canvas.drawOval(indicatorRectF, indicatorStrokePaint) | |
} | |
} | |
override fun onSaveInstanceState(): Parcelable? { | |
val superState = super.onSaveInstanceState() | |
val savedState = SavedState(superState) | |
savedState.progress = this.progress | |
return savedState | |
} | |
override fun onRestoreInstanceState(state: Parcelable?) { | |
state as SavedState | |
super.onRestoreInstanceState(state.superState) | |
progress = state.progress | |
} | |
private class SavedState : BaseSavedState { | |
var progress: Float = 0F | |
constructor(parcelable: Parcelable?) : super(parcelable) | |
private constructor(parcel: Parcel) : super(parcel) { | |
progress = parcel.readFloat() | |
} | |
override fun writeToParcel(parcel: Parcel, flags: Int) { | |
super.writeToParcel(parcel, flags) | |
parcel.writeFloat(progress) | |
} | |
override fun describeContents(): Int { | |
return 0 | |
} | |
companion object CREATOR : Parcelable.Creator<SavedState> { | |
override fun createFromParcel(parcel: Parcel): SavedState { | |
return SavedState(parcel) | |
} | |
override fun newArray(size: Int): Array<SavedState?> { | |
return arrayOfNulls(size) | |
} | |
} | |
} | |
private val Float.dp: Float get() = this * resources.displayMetrics.density | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment