Search code examples
androidandroid-layoutandroid-drawableandroid-appwidget

Setting widget background to programmatically generated gradient


I'm struggling with making my widget to look pretty, but the widget fights back ;(

I have a problem with setting widget layout background to generated linear gradient.

For now, I have found how to generate linear gradient with custom "weigth" of colors for that gradient:

public static PaintDrawable createLinearGradient(final int left, final int top, final int right, final int bottom, 
                                                 final int[] colors, final float[] positions)
{
    ShapeDrawable.ShaderFactory shaderFactory = new ShapeDrawable.ShaderFactory()
    {
        @Override
        public Shader resize(int width, int height)
        {
            LinearGradient lg = new LinearGradient(left, top, right, bottom, colors, positions, Shader.TileMode.REPEAT);
            return lg;
        }
    };

    PaintDrawable gradient = new PaintDrawable();
    gradient.setShape(new RectShape());
    gradient.setShaderFactory(shaderFactory);

    return gradient;
}

And here is a way to set widget background to drawable from drawable folder:

int backgroundId =  getDrawableByName(context, "round_transparrent_background");
remoteViews.setInt(R.id.mainLayout, "setBackgroundResource", backgroundId);

I need a way to write this command as following:

Drawable background =  createLinearGradient(params ... );
remoteViews.setInt(R.id.mainLayout, "setBackgroundResource", background);

Solution

  • RemoteViews are inherently limited to certain functions. This makes some sense when you consider that any information you pass to your RemoteViews needs to travel across processes, and not all classes/data types are supported.

    There is no way to pass an arbitrary Drawable object to RemoteViews -- none of the methods support it, and Drawable in general is not a class whose data can be marshalled across processes. The reason it works for drawable resources is that the resource ID is just an integer, and Android knows how to inflate them into Bitmaps (for pngs) or their respective Drawable implementations (for anything declared with XML).

    As I see it, the only strategy that might work would be to actually draw the gradient into a Bitmap using the Canvas APIs and to use an ImageView in your AppWidget to act as the background. Then you would call remoteViews.setImageViewBitmap() to set the content of the ImageView.