Skip to content

Instantly share code, notes, and snippets.

@devetude
Created November 4, 2018 09:30
Show Gist options
  • Save devetude/61296bddad90fb42d9c56ecd17742f73 to your computer and use it in GitHub Desktop.
Save devetude/61296bddad90fb42d9c56ecd17742f73 to your computer and use it in GitHub Desktop.
HighlightView.kt
package com.linecorp.highlightview
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.support.annotation.AttrRes
import android.support.constraint.ConstraintLayout
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
class HighlightView : ConstraintLayout {
private lateinit var view: View
private lateinit var styledAttrs: TypedArray
private val paint: Paint
get() = Paint().apply {
flags = Paint.ANTI_ALIAS_FLAG
xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
}
private val layoutInflater: LayoutInflater
get() = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
private val highlightPadding: Int
get() = if (::styledAttrs.isInitialized) {
styledAttrs.getDimensionPixelSize(
R.styleable.HighlightView_highlight_padding,
DEFAULT_HIGHLIGHT_PADDING
)
} else {
DEFAULT_HIGHLIGHT_PADDING
}
private var target: HighlightTarget? = null
constructor(context: Context) : super(context) {
initView()
}
constructor(
context: Context,
attrs: AttributeSet
) : super(context, attrs) {
initView(attrs)
}
constructor(
context: Context,
attrs: AttributeSet,
@AttrRes defStyleAttr: Int
) : super(
context,
attrs,
defStyleAttr
) {
initView(attrs, defStyleAttr)
}
override fun onDraw(canvas: Canvas?) {
canvas?.apply {
drawBackgroundColor()
maybeDrawHighlightCircle()
}
}
private fun initView(
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = UNSET_ATTRIBUTE_RESOURCE
) {
setWillNotDraw(false)
setLayerType(LAYER_TYPE_HARDWARE, null /* paint */)
view = layoutInflater
.inflate(
R.layout.highlight_view,
this /* root */,
false /* attachToRoot */
)
.maybeApplyStyledAttributes(attrs, defStyleAttr)
.also(::addView)
}
fun highlight(target: HighlightTarget) {
this.target = target
invalidate()
}
@SuppressLint(value = ["Recycle"])
private fun View.maybeApplyStyledAttributes(
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int
): View {
if (attrs == null) {
return this
}
styledAttrs = if (defStyleAttr == UNSET_ATTRIBUTE_RESOURCE) {
context.obtainStyledAttributes(
attrs,
R.styleable.HighlightView
)
} else {
context.obtainStyledAttributes(
attrs,
R.styleable.HighlightView,
defStyleAttr,
0 /* defStyleRes */
)
}
return this
}
private fun Canvas.drawBackgroundColor() =
background?.draw(this /* canvas */)
?: drawColor(DEFAULT_BACKGROUND_COLOR)
private fun Canvas.maybeDrawHighlightCircle() =
target?.viewReference?.get()?.let { targetView: View ->
drawCircle(
targetView.x,
targetView.y,
highlightPadding.toFloat(),
paint
)
}
companion object {
private const val UNSET_ATTRIBUTE_RESOURCE = -1
private const val DEFAULT_HIGHLIGHT_PADDING = 0
private val DEFAULT_BACKGROUND_COLOR =
Color.parseColor("#66000000" /* colorString */)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment