Last active
January 12, 2022 18:15
-
-
Save hector6872/e8847ed65fa3bd60516e2daaa48a3113 to your computer and use it in GitHub Desktop.
Triangle View for Android in Kotlin
This file contains hidden or 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
<?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> |
This file contains hidden or 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
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