Skip to content

Instantly share code, notes, and snippets.

@hector6872
Last active January 12, 2022 18:15
Show Gist options
  • Save hector6872/e8847ed65fa3bd60516e2daaa48a3113 to your computer and use it in GitHub Desktop.
Save hector6872/e8847ed65fa3bd60516e2daaa48a3113 to your computer and use it in GitHub Desktop.
Triangle View for Android in Kotlin
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TriangleView">
<attr name="tv_type">
<enum name="topLeft" value="0" />
<enum name="topRight" value="1" />
<enum name="bottomLeft" value="2" />
<enum name="bottomRight" value="3" />
<enum name="left" value="4" />
<enum name="up" value="5" />
<enum name="right" value="6" />
<enum name="down" value="7" />
<enum name="leftNarrow" value="8" />
<enum name="upNarrow" value="9" />
<enum name="rightNarrow" value="10" />
<enum name="downNarrow" value="11" />
</attr>
<attr name="tv_color" format="color" />
</declare-styleable>
</resources>
class TriangleView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
private val paint by lazy { Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL } }
private val path: Path = Path()
@ColorInt
var color: Int = Color.TRANSPARENT
set(value) {
field = value
invalidate()
}
var type: Type = Type.DEFAULT
set(value) {
field = value
invalidate()
}
init {
attrs?.use(context, R.styleable.TriangleView) {
type = Type.safeOf(getInt(R.styleable.TriangleView_tv_type, Type.DEFAULT.value))
color = getColor(R.styleable.TriangleView_tv_color, color)
}
}
override fun onDraw(canvas: Canvas) = super.onDraw(canvas).also {
val widthF = width.toFloat()
val heightF = height.toFloat()
when (type) {
TOP_LEFT -> path.run {
moveTo(0f, 0f)
lineTo(0f, heightF)
lineTo(widthF, 0f)
}
TOP_RIGHT -> path.run {
moveTo(0f, 0f)
lineTo(widthF, heightF)
lineTo(widthF, 0f)
}
BOTTOM_LEFT -> path.run {
moveTo(0f, 0f)
lineTo(0f, heightF)
lineTo(widthF, heightF)
}
BOTTOM_RIGHT -> path.run {
moveTo(0f, heightF)
lineTo(widthF, heightF)
lineTo(widthF, 0f)
}
LEFT,
LEFT_NARROW -> path.run {
moveTo(widthF, 0f)
lineTo(widthF.div2ifOrZero(type.isLeftNarrow), heightF.div2())
lineTo(widthF, heightF)
}
UP,
UP_NARROW -> path.run {
moveTo(0f, heightF)
lineTo(widthF.div2(), heightF.div2ifOrZero(type.isUpNarrow))
lineTo(widthF, heightF)
}
RIGHT,
RIGHT_NARROW -> path.run {
moveTo(0f, 0f)
lineTo(widthF.div2if(type.isRightNarrow), heightF.div2())
lineTo(0f, heightF)
}
DOWN,
DOWN_NARROW -> path.run {
moveTo(0f, 0f)
lineTo(widthF.div2(), heightF.div2if(type.isDownNarrow))
lineTo(widthF, 0f)
}
}.also { path.close() }
canvas.drawPath(path, paint.apply { color = [email protected] })
}
enum class Type(val value: Int) {
TOP_LEFT(0),
TOP_RIGHT(1),
BOTTOM_LEFT(2),
BOTTOM_RIGHT(3),
LEFT(4),
UP(5),
RIGHT(6),
DOWN(7),
LEFT_NARROW(8),
UP_NARROW(9),
RIGHT_NARROW(10),
DOWN_NARROW(11);
companion object {
val DEFAULT: Type = TOP_LEFT
fun safeOf(value: Int?): Type = values().firstOrNull { it.value == value } ?: DEFAULT
}
val isLeftNarrow: Boolean get() = this == LEFT_NARROW
val isUpNarrow: Boolean get() = this == UP_NARROW
val isRightNarrow: Boolean get() = this == RIGHT_NARROW
val isDownNarrow: Boolean get() = this == DOWN_NARROW
}
}
inline fun AttributeSet.use(context: Context, @StyleableRes attrs: IntArray, block: TypedArray.() -> Unit) {
context.obtainStyledAttributes(this, attrs).use { typedArray -> block(typedArray) }
}
private fun Float.div2if(condition: Boolean): Float = if (condition) this.div2() else this
private fun Float.div2ifOrZero(condition: Boolean): Float = if (condition) this.div2() else 0f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment