Create layer list with rounded corners programmati

2019-02-09 02:14发布

问题:

I am currently trying to convert the following XML to be created programmatically so that I can set the top corners and bottom corners as needed throughout my project. It is a simple Layer list that has two rectangles; one on top of another. I would like to use this as a background for a few different views so it is important that the result scales.

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:bottom="20dp">
        <shape android:shape="rectangle" >
            <size android:height="20dp" />
            <solid android:color="#969595" />
            <corners
                android:radius = "0dp"
                android:topLeftRadius="5dp"
                android:topRightRadius="5dp" />
        </shape>
    </item>
    <item android:top="20dp">
        <shape android:shape="rectangle" >
            <size android:height="20dp" />
            <solid android:color="#7B7979" />
            <corners
                android:radius = "0dp"
                android:bottomLeftRadius="5dp"
                android:bottomRightRadius="5dp" />
        </shape>
    </item>
</layer-list>

This approach does work but I need a separate XML for each shape depending upon whether I want the top, bottom, both, or none of the corners rounded.

my current attempts at creating the same drawable have yielded nothing more than two rectangles with one on top of the other. I could not figure out how to set the positions of the rectangles. I could see no visible change regardless of what the bounds of the shape were set to. Any suggestions would be greatly appreciated.

// Usage: 
setBackgroundDrawable(new DualColorStateDrawable(0, 10f));

...

private final int topColorUnselected = Color.RED;
private final int bottomColorUnselected = Color.GREEN;
private final int topColorSelected = Color.YELLOW;
private final int bottomColorSelected = Color.BLUE;
private final int m_nZERO_RADIUS = 0;

class DualColorStateDrawable extends StateListDrawable
{
    public NYWTableViewCellStateDrawable(float topRadius, float bottomRadius){
        addState(new int[] { -android.R.attr.state_pressed }, 
                 createListWithSelectedState(false, topRadius, bottomRadius));
        addState(new int[] { android.R.attr.state_pressed }, 
                 createListWithSelectedState(true, topRadius, bottomRadius));   
    }

    public Drawable createListWithSelectedState(
        boolean isSelected, float topRadius, float bottomRadius){

        int topColor, bottomColor;

        if (isSelected) {
            topColor = topColorSelected;
            bottomColor = bottomColorSelected;
        } else {
            topColor = topColorUnselected;
            bottomColor = bottomColorUnselected;
        }

        int x = 10;
        int y = 10;
        int width = 20;
        int height = 20;

        RoundRectShape _rrsTopShape = 
            new RoundRectShape(getRadii(topRadius, m_nZERO_RADIUS), null, null);
        CustomShapeDrawable _csdTopShape = 
            new CustomShapeDrawable(_rrsTopShape, topColor);
        RoundRectShape _rrsBottomShape = 
            new RoundRectShape(getRadii(m_nZERO_RADIUS, bottomRadius), null, null);
        CustomShapeDrawable _csdBottomShape = 
            new CustomShapeDrawable(_rrsBottomShape, bottomColor);
        _csdBottomShape.setBounds(x, y, x + width, y + height);

        return new LayerDrawable(new Drawable[] {_csdTopShape, _csdBottomShape});
    }

    private float[] getRadii(float top, float bottom) 
    {
        return new float[] { top, top, //
                top, top, //
                bottom, bottom, //
                bottom, bottom //
        };
    }

    class CustomShapeDrawable extends ShapeDrawable {
        private final Paint fillpaint;

        public CustomShapeDrawable(Shape s, int fill) {
            super(s);
            fillpaint = new Paint(this.getPaint());
            fillpaint.setColor(fill);
        }

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

回答1:

You're looking for LayerDrawable's setLayerInset in order to be able to set one rectangle above the other.

See below:

float radius = 5.0f;

float[] m_arrfTopHalfOuterRadii = 
    new float[] {radius, radius, radius, radius, 0, 0, 0, 0};
float[] m_arrfBottomHalfOuterRadii = 
    new float[] {0, 0, 0, 0, radius, radius, radius, radius};

int m_nTopColor = Color.BLUE;
int m_nBottomColor = Color.CYAN;

int m_nCellHeight = 40;

public Drawable drawbg()
{
    RoundRectShape top_round_rect = 
        new RoundRectShape(m_arrfTopHalfOuterRadii, null, null);
    ShapeDrawable top_shape_drawable = new ShapeDrawable(top_round_rect);
    top_shape_drawable.getPaint().setColor(m_nTopColor); 

    RoundRectShape bottom_round_rect = 
        new RoundRectShape(m_arrfBottomHalfOuterRadii, null, null);
    ShapeDrawable bottom_shape_drawable = new ShapeDrawable(bottom_round_rect);
    bottom_shape_drawable.getPaint().setColor(m_nBottomColor);

    Drawable[] drawarray = {top_shape_drawable, bottom_shape_drawable};
    LayerDrawable layerdrawable = new LayerDrawable(drawarray);

    int _nHalfOfCellHeight = m_nCellHeight/2; 
    layerdrawable.setLayerInset(0, 0, 0, 0, _nHalfOfCellHeight); //top half
    layerdrawable.setLayerInset(1, 0, _nHalfOfCellHeight, 0, 0); //bottom half

    return layerdrawable;
}