Make gradient start further away from end of view with GradientDrawable

Viewed 247

I am trying to set the background of a view to have a gradient whose color is generated from the Palette api

The gradient will go from a solid and fade out but I want the solid portion to take up a majority of the background. Right now it starts solid and then gradually fades out over the view width, I want it to where it will start fading out from around the center of the view width.

Here is what I do

            Palette.from(resource!!.toBitmap()).generate {
                if (it != null) {
                    val paletteColor = it.getDarkVibrantColor("#000000".toColorInt())

                    val gradientDrawable = GradientDrawable(
                        GradientDrawable.Orientation.LEFT_RIGHT,
                        intArrayOf(colorWithAlpha(paletteColor, 0f), colorWithAlpha(paletteColor, 1.0f))
                    )
                    gradientDrawable.cornerRadius = 0f
                    _contentTextBackground.background = gradientDrawable
                }
            }

Is there a way to set the gradient to start further away from the end of the view?

6 Answers

You can do this via XML to change centerX and centerY attributes of GradientDrawable. But sadly, with GradientDrawable, this is not possible programmatically as discussed on Google Issue Tracker.

For APIs below 29, try using a ShapeDrawable with a LinearGradient Shader as a background. This will give you fine-level control over the transition of the colors.

For API 29+, GradientDrawable allows for similar fine-level control over color transitions with setColors().

private fun getBackgroundGradient(width: Int): Drawable {
    val colors = intArrayOf(Color.BLUE and 0x00FFFFFF, Color.BLUE, Color.BLUE)
    val offsets = floatArrayOf(0.0f, 0.7f, 1.0f)

    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Oddly, there is no constructor that accepts the offsets.
        GradientDrawable().apply {
            orientation = GradientDrawable.Orientation.LEFT_RIGHT
            setColors(colors, offsets)
        }
    } else {
        val shader: Shader = LinearGradient(
            0f, 0f, width.toFloat(), 1f, colors, offsets, Shader.TileMode.CLAMP
        )
        val shape = ShapeDrawable(RectShape())
        shape.paint.shader = shader
        shape
    }
}

I used 0.7f as the "center" to make a better (IMO) color transition near the 50% mark, but that value could easily be 0.5f or any other value between 0f and 1.0f.

In the following image, the horizontal bar is the width of the screen and is just a View. The vertical red line splits the screen into two to mark the transition.

enter image description here

As stated by @Abdul Mateen you cannot change the attributes in Graient Drawable. This is only possible if you do it via XML. But there is a workaround:

You could theoretically split your background view in half. Then you have two views on which you could then change the color, based on the Palette Library. One view would then be the solid color and the other one would have to have the Gradient in the Background. If you configure that correctly, you should have a perfect gradient from the middle.

Try extending GradientDrawable and set fades and colour as per you needs.

package com.example.testApp;

import android.app.Activity;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.view.View;

public class TetApp extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    View v = findViewById(R.id.btn);
    v.setBackgroundDrawable( new DrawableGradient(new int[] { 0xff666666, 0xff111111, 0xffffffff }, 0).SetTransparency(10));

}

public class DrawableGradient extends GradientDrawable {
    DrawableGradient(int[] colors, int cornerRadius) {
        super(GradientDrawable.Orientation.TOP_BOTTOM, colors);

        try {
            this.setShape(GradientDrawable.RECTANGLE);
            this.setGradientType(GradientDrawable.LINEAR_GRADIENT);
            this.setCornerRadius(cornerRadius);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public DrawableGradient SetTransparency(int transparencyPercent) {
        this.setAlpha(255 - ((255 * transparencyPercent) / 100));

        return this;
    }
}
}

reference from this: https://stackoverflow.com/a/5241693/14964046

Just add the solid color in array one more like below

val gradientDrawable = GradientDrawable(
    GradientDrawable.Orientation.LEFT_RIGHT,
    intArrayOf(colorWithAlpha(paletteColor, 0f), colorWithAlpha(paletteColor, 1.0f),  colorWithAlpha(paletteColor, 1.0f))
                    )

Its not elegant, but works :-D

What I ended up doing was what Mike suggested in the comments was to just add more of the solid color the the color array of the GradientDrawable

so it looked like this

val gradientDrawable = GradientDrawable(
                        GradientDrawable.Orientation.LEFT_RIGHT,
                        intArrayOf(colorWithAlpha(paletteColor, 0f), colorWithAlpha(paletteColor, 1.0f), colorWithAlpha(paletteColor, 1.0f), colorWithAlpha(paletteColor, 1.0f))
                    )
Related