Android - how to define ShapeDrawables programmatically?
Asked Answered
M

3

28

What I'm trying to achieve is to use a Drawable with a couple of layers inside it, but control some values at runtime such as the startColor for the gradient. Here's what I have in my_layered_shape.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  <item>
    <shape android:shape="rectangle">
      <stroke android:width="1dp" android:color="#FF000000" />
      <solid android:color="#FFFFFFFF" />
    </shape>
  </item>
  <item android:top="1dp" android:bottom="1dp"> 
    <shape android:shape="rectangle">
    <stroke android:width="1dp" android:color="#FF000000" />
    <gradient
      android:startColor="#FFFFFFFF"
      android:centerColor="#FFFFFF88"
      android:endColor="#FFFFFFFF"
      android:gradientRadius="250"
      android:centerX="1"
      android:centerY="0"
      android:angle="315"
    />            
    </shape>
  </item>
</layer-list>

And if I use mMyImageView.setBackgroundResource(R.drawable.my_layered_shape) it works. I don't mind splitting the xml if I have to, or doing the whole thing programatically as long as there's a way to get at the various color values. The concept I'm going for programmatically (i.e. my best shot at doing the same in code as this xml) is:

Drawable[] layers = new Drawable[2];

ShapeDrawable sd1 = new ShapeDrawable(new RectShape());
sd1.getPaint().setColor(0xFFFFFFFF);
sd1.getPaint().setStyle(Style.STROKE);
sd1.getPaint().setStrokeWidth(1);
// sd1.getPaint().somehow_set_stroke_color?

ShapeDrawable sd2 = new ShapeDrawable(new RectShape());
sd2.getPaint().setColor(0xFF000000);
sd2.getPaint().setStyle(Style.STROKE);
// sd2.getPaint().somehow_set_stroke_color?
// sd2.getPaint().somehow_set_gradient_params?

layers[0] = sd1;
layers[1] = sd2;
LayerDrawable composite = new LayerDrawable(layers);
mMyImageView.setBackgroundDrawable(composite);

Thanks.

Merriott answered 22/8, 2011 at 16:35 Comment(0)
S
26

It seems that is does not work with ShapeDrawable, but take a look at my GradientDrawable example:

GradientDrawable gd = new GradientDrawable(Orientation.BOTTOM_TOP, new int[]{Color.RED, Color.GREEN});
gd.setStroke(10, Color.BLUE);

You may also need following method:

gd.setGradientCenter(float x, float y);
gd.setGradientRadius(float gradientRadius);
Scoff answered 2/12, 2011 at 10:12 Comment(1)
strangely, GradientDrawable class don't have 'setPadding' method, is there any work around ?Ricercare
S
5

Just gonna leave this here... Not tested yet

 /**
 * Created by Nedo on 09.04.2015.
 */
public class ShapeBuilder {

    public static Drawable generateSelectorFromDrawables(Drawable pressed, Drawable normal) {
        StateListDrawable states = new StateListDrawable();
        states.addState(new int[]{ -android.R.attr.state_focused, -android.R.attr.state_pressed, -android.R.attr.state_selected}, normal);
        states.addState(new int[]{ android.R.attr.state_pressed}, pressed);
        states.addState(new int[]{ android.R.attr.state_focused}, pressed);
        states.addState(new int[]{ android.R.attr.state_selected}, pressed);

        return states;
    }

    public static Drawable generateShape(String colorTop, String colorBot, String colorStroke, int stokeSize, float strokeRadius) {
        int top, bot, stroke;
        top = Color.parseColor(colorTop);
        bot = Color.parseColor(colorBot);
        stroke = Color.parseColor(colorStroke);

        GradientDrawable drawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, new int[]{top, bot});
        drawable.setStroke(stokeSize, stroke);
        drawable.setCornerRadius(strokeRadius);

        return drawable;
    }

    public static Drawable buildSelectorShapeFromColors(String colorNormalStroke, String colorNormalBackTop, String colorNormalBackBot,
                                                        String colorPressedStroke, String colorPressedBackTop, String colorPressedBackBot,
                                                        int strokeSize, float strokeRadius) {

        Drawable pressed = generateShape(colorPressedBackTop, colorPressedBackBot, colorPressedStroke, strokeSize, strokeRadius);
        Drawable normal = generateShape(colorNormalBackTop, colorNormalBackBot, colorNormalStroke, strokeSize, strokeRadius);
        return generateSelectorFromDrawables(pressed, normal);
    }
}

Edit: tested Now, had one mistake. You actually have to describe every single state. If you group states they will only be triggered if all of them accure at once...

Selfsown answered 9/4, 2015 at 8:26 Comment(0)
U
1

Created by Nedo on 09.04.2015.

public class ShapeBuilder {

    public static Drawable generateSelectorFromDrawables(Drawable pressed, Drawable normal) {
        StateListDrawable states = new StateListDrawable();
        states.addState(new int[]{ -android.R.attr.state_focused, -android.R.attr.state_pressed, -android.R.attr.state_selected}, normal);
        states.addState(new int[]{ android.R.attr.state_pressed}, pressed);
        states.addState(new int[]{ android.R.attr.state_focused}, pressed);
        states.addState(new int[]{ android.R.attr.state_selected}, pressed);

        return states;
    }

    public static Drawable generateShape(String colorTop, String colorBot, String colorStroke, int stokeSize, float strokeRadius) {
        int top, bot, stroke;
        top = Color.parseColor(colorTop);
        bot = Color.parseColor(colorBot);
        stroke = Color.parseColor(colorStroke);

        GradientDrawable drawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, new int[]{top, bot});
        drawable.setStroke(stokeSize, stroke);
        drawable.setCornerRadius(strokeRadius);

        return drawable;
    }

    public static Drawable buildSelectorShapeFromColors(String colorNormalStroke, String colorNormalBackTop, String colorNormalBackBot,
                                                        String colorPressedStroke, String colorPressedBackTop, String colorPressedBackBot,
                                                        int strokeSize, float strokeRadius) {

        Drawable pressed = generateShape(colorPressedBackTop, colorPressedBackBot, colorPressedStroke, strokeSize, strokeRadius);
        Drawable normal = generateShape(colorNormalBackTop, colorNormalBackBot, colorNormalStroke, strokeSize, strokeRadius);
        return generateSelectorFromDrawables(pressed, normal);
    }
}

Edit: tested Now, had one mistake.

Utrecht answered 12/4 at 17:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.