Search code examples
androidandroid-custom-viewandroid-drawableandroid-controls

StateListDrawable with LayerDrawable created programatically not working on Android 4.0+


I am trying to create an option group with coloured squares for the user to choose one. It is working on a 3.2 device and looking like in this picture: enter image description here

The code is something like:

for (int i = 0; i < COLORS.length; i++) {
        CheckBox box = new CheckBox(context);
        box.setBackgroundDrawable(getColorOption(context, COLORS[i]));
        box.setButtonDrawable(android.R.color.transparent);

And then, in the getColorOption function I create the StateListDrawable:

    StateListDrawable slDrawable = new StateListDrawable();

    LayerDrawable checkedDrawable = new LayerDrawable(new Drawable[] {
            new SelectFrameShapeDrawable(transparentColor, lightRedColor),
            new SquareShapeDrawable(color) });
    LayerDrawable uncheckedDrawable = new LayerDrawable(new Drawable[] {
                    new SelectFrameShapeDrawable(transparentColor, transparentColor),
                    new SquareShapeDrawable(color) });
    slDrawable.addState(new int[] { android.R.attr.state_checked },
            checkedDrawable);
    slDrawable.addState(new int[] { -android.R.attr.state_checked }, uncheckedDrawable);
    return slDrawable;

The SquareShapeDrawable class is a ShapeDrawable:

public class SquareShapeDrawable extends ShapeDrawable {
    private final Paint fillpaint;

    public SquareShapeDrawable(int color) {
        super(new RectShape());
        fillpaint = new Paint(this.getPaint());
        fillpaint.setColor(color);
    }

    @Override
    protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
        shape.draw(canvas, fillpaint);
    }
}

And the SelectFrameShapeDrawable is:

private class SelectFrameShapeDrawable extends ShapeDrawable {
private final Paint fillpaint, strokepaint;

public SelectFrameShapeDrawable(int fill, int stroke) {
        super(new RectShape());
        strokepaint = new Paint(this.getPaint());
        strokepaint.setStyle(Paint.Style.STROKE);

        strokepaint.setStrokeWidth((int) (getResources()
                .getDisplayMetrics().density + 0.5f));
        strokepaint.setColor(stroke);
        int padding = (int) (4 * getResources().getDisplayMetrics().density + 0.5f);
        setPadding(padding, padding, padding, padding);

        fillpaint = new Paint(strokepaint);
        fillpaint.setColor(fill);
    }

    @Override
    protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
        if (strokepaint != null)
            shape.draw(canvas, strokepaint);
        shape.draw(canvas, fillpaint);
    }
}

On a 4.2 device all the squares are black and do not change when checked: enter image description here

The problem seems to be when adding the drawables to the StateListDrawable... Any idea how to solve this?


Solution

  • I solved the black squares issue by removing the custom classes that extended ShapeDrawable and replaced them with the code bellow that uses the ShapeDrawable class directly. This code seems to work on all platforms.

    It is weird though that the original issue was present on 4.2 and not on 3.2. My original source of inspiration was this: http://www.betaful.com/2012/01/programmatic-shapes-in-android/

        ShapeDrawable selectFrame = new ShapeDrawable();
        selectFrame.setShape(new RectShape());
        selectFrame.getPaint().setColor(lightRedColor);
        selectFrame.getPaint().setStyle(Paint.Style.STROKE);
        selectFrame.getPaint().setStrokeWidth((int) (getResources().getDisplayMetrics().density + 0.5f));
        int padding = (int) (4 * getResources().getDisplayMetrics().density + 0.5f);
        selectFrame.setPadding(padding, padding, padding, padding);
    
        ShapeDrawable square = new ShapeDrawable();
        square.setShape(new RectShape());
        square.getPaint().setColor(color);
    
        LayerDrawable checkedDrawable = new LayerDrawable(new Drawable[] {
                selectFrame, square });
    ...