33

I'm trying out the android ScaleDrawable

But it doesn't seem to work... I created the xml as in the documentation example and I have a logo.png in the drawable folder

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/logo"
    android:scaleGravity="center_vertical|center_horizontal"
    android:scaleHeight="80%"
    android:scaleWidth="80%" />

I saved this as logo2.xml in the drawable folder then I have a LinearLayout with an ImageView and set the src of the ImageView to "@drawable/logo2" but the logo doesn't appear...Am I doing something wrong here? How do you actually use the scale element?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
stephenteh
  • 483
  • 1
  • 5
  • 8

5 Answers5

35

Just today I faced the same problem. The ScaleDrawable does not seem to work. After some investigation I've found the solution:

If you look at the documentation you can find this phrase: "A Drawable that changes the size of another Drawable based on its current level value." That's it.

It became clear after I found the onBoundsChange() function uses the strange level variable.

For you the code would be something like this:

Resources res = getResources();
ScaleDrawable sd = (ScaleDrawable) res.getDrawable(R.drawable.logo2);
Drawable d = sd.getDrawable();

d.setLevel(1);

ImageView iv = new ImageView(this);
iv.setImageDrawable(sd);
iv.setAdjustViewBounds(true); 
iv.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

setContentView(iv);

Update: I think the problem in the draw() function. Because after an initialization the level variable is 0:

public void draw(Canvas canvas) {
    if (mScaleState.mDrawable.getLevel() != 0)
        mScaleState.mDrawable.draw(canvas);
}

Update: Maybe then this code may help you:

private void useScaledImage() {
    Resources res = getResources();
    BitmapDrawable bd = (BitmapDrawable)res.getDrawable(R.drawable.sun);
    Bitmap b = Bitmap.createScaledBitmap(bd.getBitmap(),
                         (int) (bd.getIntrinsicHeight() * 0.7),
                         (int) (bd.getIntrinsicWidth() * 0.7),
                         false);

    LinearLayout l = new LinearLayout(this);
    ImageView iv = new ImageView(this);

    iv.setImageDrawable(new BitmapDrawable(b));
    iv.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

    l.addView(iv);

    setContentView(l);
}
m039
  • 1,329
  • 13
  • 11
  • 1
    thanks for your reply, seems like that's not what I expect from the ScaleDrawable. I thought to have a single bitmap(png/jpg/...) and then I can scale this bitmap up/down in xml then use it in difference layout instead of having multiple bitmap with difference sizes. Any suggestions that you can do this in android? – stephenteh Apr 04 '11 at 09:12
  • @stephenteh As for me, I want something like thumbnail images from the ScaleDrawable. I found an interesting solution for you. Just to use createScaledBitmap from the source (I added example code to the whole answer. Here it does not fit.). You can change 0.7 value to a one frome an integer resourses (e.g. R.integer.myvalue). And I've found two interesting functions: setScaleX(..) and setScaleY(..) from the View class. But they are from the 11 API. – m039 Apr 04 '11 at 19:20
  • Thank you, you are a gentleman and a scholar. Should we report this as a bug? Seems unintuitive to make a Drawable *invisible* by default. – phreakhead Feb 14 '13 at 22:45
  • 2
    @phreakhead thanks, maybe the best solution is to add a note to the documentation. I think who wrote this code has his own intentions, but it is better to document it properly as many people find it is not obvious. – m039 Feb 15 '13 at 10:40
  • 2
    Is there any xml-only workaround? A library I'm using provides a view which takes a drawable as an attribute, and doesn't provide access to the drawable in code. Thanks for the answer in any case. – Daniel Lubarov Oct 28 '14 at 22:30
  • You can always create custom view (with custom xml attributes) extending your view, unless it is marked final. – m039 Jan 01 '15 at 15:38
  • The documentation is still not fixed. I wanted to make a square that took up half the containing drawable, but the level isn't available in xml until very recent API (24 I think). The example in the Google docs shows nothing if you use it. – Mitch Apr 28 '17 at 18:13
  • 10 year later and this still doesn't work :\ – t3chb0t Jan 14 '21 at 17:48
7

Use inset drawable instead of scale drawable

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android" 
    android:drawable="@drawable/logo"
    android:insetTop="2dp"
    android:insetLeft="2dp"  
    android:insetRight="2dp"
    android:insetBottom="2dp"
    >
SMR
  • 6,628
  • 2
  • 35
  • 56
teo ten
  • 79
  • 1
  • 2
3

You need to add level in your xml.

android:level="1"
Artemy
  • 229
  • 2
  • 5
1

To answer to the initial question, you just have to initialize your ScaleDrawable's Level with 10 000 in your onCreate. You get your ImageView, ImageButton's drawable using getIcon or getBackground (depends if you set it as a source or a background) and then call setLevel on it. For a MenuItem, the code looks like :

    editMenuItem = menu.findItem(R.id.action_edit);
    menuItemEdit_ScaleDrawable = (ScaleDrawable) editMenuItem.getIcon();
    //when playing with scaleDrawable always initialize the level
    menuItemEdit_ScaleDrawable.setLevel(10000);

I use ScaleDrawable when running animation that changes the size of the drawable. For your usecase, I definitely prefer managing the size of the component not the drawable displayed by the component.

1

ScaleDrawable not only allows you to scale a drawable, it also allows you to control the scale using setLevel on the ScaleDrawable itself. But the ScaleDrawable doesn't change the intrinsic width and height of the drawable As @m039 pointed out, the ScaleDrawable source actually does a strange thing: when the original drawable's level is set to 0, the scaleDrawable itself won't draw.

To take effect of the scale, you have to do something like this:

ScaleDrawable scaleDrawable = (ScaleDrawable) imageView.getDrawable();
scaleDrawable.setLevel(10000);
or 
scaleDrawable.setLevel(5000);
ssynhtn
  • 1,307
  • 12
  • 18