Skip to content

Instantly share code, notes, and snippets.

@darnmason
Created March 20, 2018 23:44
Show Gist options
  • Select an option

  • Save darnmason/e9c33d5c310d4699e742099f5319d27f to your computer and use it in GitHub Desktop.

Select an option

Save darnmason/e9c33d5c310d4699e742099f5319d27f to your computer and use it in GitHub Desktop.

Revisions

  1. darnmason created this gist Mar 20, 2018.
    63 changes: 63 additions & 0 deletions CircularShadowView.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@
    import android.content.Context
    import android.graphics.Color
    import android.graphics.RadialGradient
    import android.graphics.Shader
    import android.graphics.drawable.PaintDrawable
    import android.graphics.drawable.ShapeDrawable
    import android.graphics.drawable.shapes.RectShape
    import android.util.AttributeSet
    import android.view.Gravity.*
    import android.widget.FrameLayout

    class CircularShadowView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) {

    private var customDepth: Float? = null
    private var endColor = Color.TRANSPARENT
    private var startColor = Color.BLACK
    private var gravity = BOTTOM

    private val shaderFactory = object : ShapeDrawable.ShaderFactory() {
    override fun resize(width: Int, height: Int): Shader {
    val x: Double
    val y: Double
    val radius: Double
    val depth: Float
    when (gravity) {
    BOTTOM, TOP -> {
    depth = customDepth ?: height.toFloat()
    x = width.toDouble() / 2
    radius = ((Math.pow(depth.toDouble(), 2.0) + Math.pow(x, 2.0)) / (2 * depth))
    y = if (gravity == BOTTOM) height + radius - depth else -radius + depth
    }
    else -> {
    depth = customDepth ?: width.toFloat()
    y = height.toDouble() / 2
    radius = ((Math.pow(depth.toDouble(), 2.0) + Math.pow(y, 2.0)) / (2 * depth))
    x = if (gravity == LEFT) -radius + depth else width + radius - depth
    }
    }
    val start = (radius - depth) / radius
    return RadialGradient(x.toFloat(), y.toFloat(), radius.toFloat(),
    intArrayOf(startColor, startColor, endColor),
    floatArrayOf(0f, start.toFloat(), 1f),
    Shader.TileMode.CLAMP)
    }
    }

    init {
    if (attrs != null) {
    val a = context.obtainStyledAttributes(attrs, R.styleable.CircularShadowView)
    if (a.hasValue(R.styleable.CircularShadowView_depth)) {
    customDepth = a.getDimension(R.styleable.CircularShadowView_depth, 0f)
    }
    endColor = a.getColor(R.styleable.CircularShadowView_endColor, endColor)
    startColor = a.getColor(R.styleable.CircularShadowView_startColor, startColor)
    gravity = a.getInt(R.styleable.CircularShadowView_gravity, gravity)
    a.recycle()
    }
    val drawable = PaintDrawable()
    drawable.shape = RectShape()
    drawable.shaderFactory = shaderFactory
    background = drawable
    }
    }
    14 changes: 14 additions & 0 deletions attrs.xml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <declare-styleable name="CircularShadowView">
    <attr name="gravity">
    <flag name="bottom" value="80" />
    <flag name="left" value="3" />
    <flag name="right" value="5" />
    <flag name="top" value="48" />
    </attr>
    <attr name="depth" format="dimension" />
    <attr name="startColor" format="color" />
    <attr name="endColor" format="color" />
    </declare-styleable>
    </resources>