Search code examples
androidgradientradial-gradients

Android Gradient border?


Task:

Want to accomplish gradient BORDER...

Start color starts from blue circle edge and end color ends on red ring edge.

enter image description here

I tried with shape oval, and ring and radial gradient. I need gradient that starts from edge of the circle (not from the centre) and expand to the end color. I am interested is it even possible to do that with radial gradient. What am I missing?

So far I made it like this:

<!-- Added shadow -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:width="85dp"
        android:height="85dp">

        <shape
            android:shape="ring"
            android:thickness="10dp"
            android:useLevel="false">

            <gradient
                android:endColor="@android:color/transparent"
                android:gradientRadius="37.5dp"
                android:startColor="@color/colorBlack"
                android:type="radial"></gradient>
        </shape>
    </item>

    <item
        android:width="64dp"
        android:height="64dp"
        android:left="11dp"
        android:top="11dp">

        <shape android:shape="oval">
            <solid android:color="@color/colorPrimaryBlue" />
        </shape>
    </item>
</layer-list>

OUTPUT:

enter image description here

Original problem is not solved. The main problem is that radial gradient starts from the centre of the circle and not from the edge.

Any more ideas?


Solution

  • I understand that you want what can be described as a corona around the disk with the disk a solid color and the corona starting with the color black at the disk's edge and transitioning to transparency radially.

    I think you will need to implement a drawable for the corona with a RadialGradient using the constructors that allows the specification of colors and color stops from the center of the disk.

    Mark Allison has a blog post entitled RadialGradient – Gradients that discusses the use of RadialGradients and their implementation.

    You can look at a similar implementation that is transparent in the center and starts with black at the edge of the disk and transitions to a separate color. You would have to compute the starting position of the black as a fraction of the overall size of the image.



    The following is a custom drawable that produces the desired effect:

    class CoronaDrawable : Drawable() {
        private val mPaint = Paint()
        private var mRadius = 0f
        private val mColors =
            intArrayOf(Color.TRANSPARENT, Color.TRANSPARENT, Color.BLACK, Color.BLACK and 0xFFFFFF)
        private val mStops = floatArrayOf(0f, 0.85f, 0.85f, 1.0f)
    
        override fun onBoundsChange(bounds: Rect) {
            super.onBoundsChange(bounds)
            mRadius = min(bounds.width(), bounds.height()) / 2f
            mPaint.shader = shaderFactory(mRadius, mRadius, mColors, mStops)
        }
    
        override fun draw(c: Canvas) {
            c.drawCircle(mRadius, mRadius, mRadius, mPaint)
        }
    
        override fun setAlpha(alpha: Int) {
        }
    
        override fun setColorFilter(filter: ColorFilter?) {
        }
    
        override fun getOpacity(): Int {
            return PixelFormat.OPAQUE
        }
    
        private fun shaderFactory(centerX: Float, centerY: Float, colors: IntArray, stops: FloatArray) =
            RadialGradient(
                centerX, centerY, min(centerX, centerY), colors, stops, Shader.TileMode.CLAMP
            )
    }
    

    which looks like this in the Android Studio layout designer as the background to a simple View:

    enter image description here

    The key take-away here is that the blank area in the center is set to transition from transparent to transparent or, otherwise, no change. This gives the empty center. At 85% of the radius the color abruptly changes to black and transitions to a transparent black.

    For API 24+, you can place this drawable into a drawable resource file as follows and use it like a regular drawable.

    corona.xml

    <drawable class="com.example.radialgradientwithstops.CoronaDrawable"/>
    

    You will have to determine how best to incorporate this drawable into your layer list or other means of presentation in your app.