How to prevent android layer drawable shapes (e.g. circle) from scaling
Asked Answered
V

3

6

I try to create a simple illustration using XML layer-list drawable.
I have two shapes, a circle and a rectangle
I want a circle not to scale.
The following is the layout:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

    <ImageView
        android:layout_margin="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/shape5"
        android:layout_gravity="center"
        android:scaleType="center"
        />
</LinearLayout>

And this is the shape5.xml drawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:top="0dp" android:left="0dp">
        <shape android:shape="rectangle" android:scaleType="center">
            <stroke android:width="2dp" android:color="@android:color/holo_red_light" />
            <size android:width="200dp" android:height="100dp"/>
        </shape>
    </item>

    <item android:top="10dp" android:left="10dp">
        <shape android:shape="oval" android:gravity="center" android:scaleType="center" >
            <stroke android:width="2dp" android:color="@android:color/holo_blue_light" />
            <corners android:radius="10dp" />
            <size android:width="20dp" android:height="20dp"/>

        </shape>
    </item>
</layer-list>

The resulting drawing looks like this:

screenshot of the rendered activity

it is clear that item android:top does the work, but nothing prevents shape from scaling. size width does not work, android:scaleType="center" does not work either.

I looked quickly at LayerDrawable.java implementation. Seems like behind the scenes an inset is created from item attributes. So I guess by calculating those I can achieve the result, I want. Is that the only way?

Update:

As per this answer, I knew that manipulating item's android:top, android:left etc, I can create a virtual inset that will scale my "shapes" as I want them. I checked this, and it is correct. So it is a workaround. I however am sorely disappointed with how counter-intuitive it is. I still hope someone can point me to a simple way to disable scaling.

Update: As per this Google Android documentation page, setting ImageView scaleType should have prevented scaling. Apparently in my case it did not work. Something is missing.

Vidette answered 31/3, 2014 at 17:16 Comment(5)
Keep it square... width=height.City
Vyger, not sure what you mean. Please elaborateVidette
A shape container is a rectangle. A square is an exception to a rectangle, where width and height are equal. So the inscribed circle (or another shape) will keep a square aspect, when the w/h ratio is 1.City
Vyger, what if I want to draw a rectangle and on one side of it a perfect circle (not ellipse which is a stretched circle. How do I go about it, in your opinion? Sample of a code would be niceVidette
I'd use 2 separate things, then. Which will look like one - we don't tell it to anybody. You make a "square" that holds a circle, without borders. This drawable is then put inside a TextView as a compound Drawable (best practice!). The textView has a background, which in turn is a 9 patch (so it stretches perfectly with the TextView's size), as its border. So, it's done. You can put the circle drawable against one of the inner sides of the TextView and have a rectangle with color border around it. You can also have some text (if the case) and have it react to clicks, too - like a button.City
B
7

Give your circle drawable the same height and width like so:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval" >
    <solid 
      android:color="@color/grey" />
    <size 
      android:width="16dp"
      android:height="16dp"/>
</shape>

The values you put as height and width do not matter too much, the important thing is that height = width. Think of them as aspect ratio and you want a ratio for a perfect circle, which is 1:1.

The reason you don't have to worry about the exact values is because the drawable will scale via the scaleType attribute.

Once you have inserted the drawable into your ImageView you can set the scaleType to scale it:

scaleType = fitCenter -> Drawable will be the same size as the ImageView but will stay a perfect circle! scaleType = centerInside -> Drawable will be height and width you specified in the parameter etc ...

Bounder answered 22/9, 2014 at 10:2 Comment(4)
He must NOT accept your answer as it does not answer initial question. As you can see, the question was to keep ratio of the circle, and this circle is ONE OF THE LAYERS. He got a rectangle as one layer and oval as the other. In this case setting size of the oval will do nothing.Buskined
Well to be fair I do not think that is possible via xml in a layer drawableBounder
well, it is possibleBuskined
You basically gave the same answer as mine, specifying the size of the layer list works in exactly the same way as I described, I don't see how our answers are different.. Giving the aspect ratio for one item in the layer list is not possible afaikBounder
R
0

Put your shape drawable into the layer-list and put android:gravity="center" in the item tag. For example, I have several TextViews in LinearLayout and their size is determined by weight, so these views are not perfect squares.

In TextView I define background: android:background="@drawable/button_selector"

Selector is defined as following:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/btn_pressed" />
    <item android:state_pressed="false" android:drawable="@android:color/transparent"/>
</selector>

Drawable:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center">
    <shape
            android:shape="oval">
        <stroke
                android:width="@dimen/mat2"
                android:color="@color/dodger_blue"/>
        <size
                android:width="@dimen/mat70"
                android:height="@dimen/mat70"/>
    </shape>
</item>
</layer-list>
Reconcilable answered 29/5, 2019 at 10:13 Comment(0)
A
-2

just put android:gravity="center" into item tag

Alcock answered 21/11, 2016 at 10:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.