0

This answer, LayerDrawable programmatically, only helped the person asking the question, didn't really teach anything. So here I am attempting to do something similar in need of a little help.

I want something very close to this:

enter image description here

  1. They have a background color specified dynamically or #eeeeee if no color is specified.
  2. They have a 1px border colored #888888 with 70% opacity (so it takes on the color of the envelope from the background)
  3. Inside that border there is a 1px white line at the top, 50% opacity.
  4. The bottom border should be replaced with a 1px black line, 90% opacity.

No since the background color is determined on the fly I found i could not use an XML drawable to create this however I think it can be done programmatically but there really aren't any good examples out there that are well explained.

Thanks in advance!

My specific question is how to create this using a layered drawable.

Community
  • 1
  • 1
jcaruso
  • 2,364
  • 1
  • 31
  • 64

2 Answers2

2

The class below achieves what you want with a custom ShapeDrawable instead of a custom LayerDrawable. Note, all the offsetting of coordinates in the drawLine calls are to prevent overlapping and ensure we see the full width of the lines around the perimeter.

public class MyShapeDrawable extends ShapeDrawable {

    private int startX, startY, endX, endY;
    private float mLineWidth = 1f;
    private Paint mLinePaint;

    public MyShapeDrawable() {

        // No color specified, so call constructor with default color White
        this(Color.WHITE);
    }

    public MyShapeDrawable(int color) {

        // use the setter defined below, to set the main color for this drawable
        setColor(color);

        // setup the Paint for drawing the lines
        mLinePaint = new Paint();
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setStrokeWidth(mLineWidth);
    }

    public void setColor(int color) {
        Paint paint = getPaint();
        paint.setColor(color);
    }

    public void setLineWidth(float lineWidth) {
        mLineWidth = lineWidth;
        mLinePaint.setStrokeWidth(mLineWidth);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        // bottom black line
        ////////////////////

        mLinePaint.setColor(Color.BLACK);
        mLinePaint.setAlpha((int) (255 * 0.9)); // Opacity 90%
        canvas.drawLine(
                getBounds().left, getBounds().bottom - mLineWidth * 0.5f,
                getBounds().right, getBounds().bottom - mLineWidth * 0.5f,
                mLinePaint);

        // translucent grey rim
        ///////////////////////

        mLinePaint.setColor(Color.parseColor("#888888"));
        mLinePaint.setAlpha((int) (255 * 0.7)); // Opacity 70%

        // top
        canvas.drawLine(
                getBounds().left, getBounds().top + mLineWidth * 0.5f,
                getBounds().right, getBounds().top + mLineWidth * 0.5f,
                mLinePaint);

        // left
        canvas.drawLine(
                getBounds().left + mLineWidth * 0.5f, getBounds().bottom - mLineWidth,
                getBounds().left + mLineWidth * 0.5f, getBounds().top + mLineWidth,
                mLinePaint);

        // right
        canvas.drawLine(
                getBounds().right - mLineWidth * 0.5f, getBounds().bottom - mLineWidth,
                getBounds().right - mLineWidth * 0.5f, getBounds().top + mLineWidth,
                mLinePaint);

        // top white line
        /////////////////

        mLinePaint.setColor(Color.WHITE);
        mLinePaint.setAlpha((int) (255 * 0.5)); // Opacity 50%
        canvas.drawLine(
                getBounds().left + mLineWidth, getBounds().top + mLineWidth * 1.5f,
                getBounds().right - mLineWidth, getBounds().top + mLineWidth * 1.5f,
                mLinePaint);
    }

You could use this class as follows:

public class Main extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_main);

        MyShapeDrawable myShapeDrawable = new MyShapeDrawable(getResources().getColor(R.color.yellow));

        FrameLayout frameLayout = (FrameLayout) findViewById(R.id.test);
        frameLayout.setBackgroundDrawable(myShapeDrawable);
    }
}
Sound Conception
  • 5,263
  • 5
  • 30
  • 47
  • Note: I've extended ShapeDrawable here, as there is no real need to use a LayerDrawable. If there's some other reason why you specifically needed a LayerDrawable, you can still use the same approach. – Sound Conception Oct 03 '14 at 04:44
  • Not only did you give me a broad outline of how to do it like @Malcolm did above but you did it inline to show me how! Thank you! – jcaruso Oct 03 '14 at 13:18
  • I will note though that everyone should look at http://stackoverflow.com/questions/11947603/setbackground-vs-setbackgrounddrawable-android before using setbackgrounddrawable in case someone else finds this helpful. – jcaruso Oct 03 '14 at 13:19
1

This shouldn't be difficult. Create the drawables you need:

  1. Background is best drawn with the ColorDrawable, for which you can call setColor().
  2. Lines can be created using the ShapeDrawable.
  3. Finally, just create a LayerDrawable using the stack of drawables you have. Use setLayerInset() to adjust the shapes so they are appearing as borders.

This is a general outline of what you need to do. I may post some code for clarification if required.

Malcolm
  • 41,014
  • 11
  • 68
  • 91