54

I have a very simple shape that I want to set the width of:

<shape android:shape="rectangle">
    <solid android:color="@color/orange"/>
    <size android:width="2dp"/>
</shape>

However, when I assign this to the background of a EditText it just shows an orange background instead of a rectangle of width 2dp. Why isn't setting the size working? I want to create a transparent drawable with a orange rectangle on the left side. I also have this wrapped in a selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <solid android:color="@color/orange"/>
            <size android:width="2dp" android:height="6dp"/>
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@android:color/transparent"/>
        </shape>
    </item>
</selector>

I've tried adding height just to see if it would change the size. It doesn't. It's like its completely ignoring the size. WTF?

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
  • How it doesnt work for you? It works like a charm. maybe the problem is in your Layout's settings? See, if your Layout has wrap_content for height and width. – Daler Jan 09 '13 at 11:26
  • 1
    It is pretty simple. is ignored and will always create a shape that fills the view. – Tadas S Apr 15 '13 at 08:55
  • Not always, certainly not with the drawableTop/Bottom/etc attributes. –  Feb 18 '14 at 15:09
  • @Daler what you're talking about it just ignores the size and fills the view. You should have tested it. There is nothing to do with Layout settings. – Farid Jul 12 '19 at 13:27

8 Answers8

39

For me, setting the gravity of the item to "center" solved the issue. For example:

<item android:id="@android:id/progress" android:gravity="center">
    <clip>
        <shape>
            <size android:height="2dp"/>
            <solid android:color="@color/my_color"/>
        </shape>
    </clip>
</item>
Simple UX Apps
  • 611
  • 2
  • 10
  • 20
11

It can work with a foreground. It seems like you can't set a background's gravity. But you can on a foreground. I checked API 21, 23 and 24 (well, with the Studio design preview) and the following places a solid circle dot on the ImageView.

<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorPrimary" />
    <size android:height="8dp" android:width="8dp" />
</shape>

With the layout snippet

    <ImageView
            android:foreground="@drawable/list_new_dot"
            android:foregroundGravity="right|center_vertical"
            tools:src="@drawable/model_1_sm"
            />

UPDATE: While it appears to work in the layout design tool, it doesn't look the same in the emulator. UPDATE 2: Since this answer has a few votes, you might want to check what I actually used in order to show a new indicator dot: https://gist.github.com/CapnSpellcheck/4d4638aefd085c703b9d990a21ddc1eb

androidguy
  • 3,005
  • 2
  • 27
  • 38
9

Just to specify the user983447's answer - the size attribute does really mean a proportion. You should set the size for all shapes in your layer-list and it'll be used a as a proportion when scaling - like the layout_weight attribute of LinearLayout. So it's better to name it not a size but a weight

Below is a work-around how to implement top and bottom white lines without using the size attribute:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#fff" />
        </shape>
    </item>
    <item android:top="1dp" android:bottom="1dp">
        <shape>
            <solid android:color="#888" />
        </shape>
    </item>
</layer-list>
CAMOBAP
  • 5,523
  • 8
  • 58
  • 93
AlexD
  • 1,021
  • 9
  • 6
  • This have bad performance due gpu overdraw (two shapes fill all pixels when you want just two lines of pixels) – Gilian Jun 21 '16 at 17:20
  • @Gilian correct me if I'm wrong, but this xml get compiled into some subclass of a Drawable via aapt, so after compilation is done it's just a java class, and performance will be the same as for any 9-patch or bitmap from gpu standpoint. So if designs require it, there is no way around – Max Ch Sep 01 '16 at 22:12
4

I found the layer-list to be very devious for a first time Androider because of the following. At first glance most would think item top,bottom,right,left attributes are FROM the top,bottom,right,left. Where a value of the following:

<item android:top="10dp">

Would net you a starting point 10dp from the top of the respective container. This is not the case. Think of it as OFF OF the top,bottom,right,left. <item android:top="10dp"> will still net you a starting point 10dp OFF OF the top, but what happens when you want to set the bottom?

<item android:bottom="20dp">

This will not get you a bottom at 20dp from the TOP, rather a bottom of 20dp OFF OF the BOTTOM of the container.

So, for example with a 100dp container, if you wanted a rectangle with a top edge starting at 20dp and a bottom edge at 40dp:

<item android:top="20" android:bottom="60dp">
  • 1
    This I actually understood that when I posted the question. There would be little point in making it all top,left relative for all values (ie top, left, bottom, right) because you could never define a shape that expands to match it's parent container without knowing the size of the container. In this particular case I had a shape that needed to be a fixed size hence I wanted to use width/height to set a dimension but the docs don't explain the coordinate system of what width/height are so you are left to guess. – chubbsondubs Mar 20 '14 at 16:35
  • Thanks man this has been a great explanation! make me understand where I was wrong and fix finally after hours the issue! but thumbs up for you! +1 – Alexiscanny May 23 '17 at 15:52
2

The size of a shape will be ignored when you use it as a background of a View. It will work when you show it via an ImageView:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#FF7700" />
    <size android:width="20dp" android:height="20dp"/>
</shape>

In your layout XML:

<!-- will have the size of 20dp x 20dp -->
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/my_shape"
    />
Cristan
  • 12,083
  • 7
  • 65
  • 69
1

I had similar problem.

Documentation ( http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape ) says:

<size>

The size of the shape. (...)

Note: The shape scales to the size of the container View proportionate to the dimensions defined here, by default. When you use the shape in an ImageView, you can restrict scaling by setting the android:scaleType to "center".

If I understand correctly, it means that "size" tag is not for setting size but for setting proportions.

user983447
  • 1,598
  • 4
  • 19
  • 36
  • 4
    So it says width/height are integers, but what you posted sounds like they might be percents (0..1) or is as big as the container's dimension (0..view.width)?! Or are you saying it makes sense and you know how it works and can explain it better than the docs? I don't fully understand your point. Either way it probably warrants a bug to either clear up the exceedingly horrible documentation or fix the code so it is actually width and height. – chubbsondubs Sep 06 '12 at 14:01
1

shape's size attribute will provide the value for drawable.getIntrinsicWidth & getIntrinsicHeight.

if the drawable's container(e.g. ImageView, TextView) has the layout param WRAP_CONTENT, then the container dimension will change if the drawable drawingState change.

but there are a bug in android framework in ImageView drawingState implementation

ImageView only update/resize its dimension by the drawable dimension on state_selected but don't on state_activated

user882729
  • 104
  • 1
  • 3
0

used this.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >

<stroke
    android:color="@color/lgray"
    android:width="1dip" />

<corners
    android:bottomLeftRadius="0dip"
    android:bottomRightRadius="0.1dip"
    android:topLeftRadius="0dip"
    android:topRightRadius="0.1dip" />

<solid android:color="@color/White" />

</shape>

put this rectangle.xml to drawable.and set your view background.

Lukas Knuth
  • 25,449
  • 15
  • 83
  • 111
Harshid
  • 5,701
  • 4
  • 37
  • 50