Mick
Mick

Reputation: 7957

ImageButtons on different sized devices

As far as I can tell (and correct me if I'm wrong), if you want to have graphical buttons that look good (with nice anti-aliasing) on multiple sized devices, you have to create different a set of different sized images and place the images inside a collection of different directories. I am looking to find a worked example showing exactly which set of directories to use and what the relative sizes need to be for those directories.

By the way, when I say ImageButtons, I mean containing an image instead of text - so 9patch images will not do the trick.

EDIT: One thing that particularly confuses me is the fact that I very often see examples (e.g. chuck258's answer) where people employ different screen densities... but if you make buttons with their width & height tuned for densities, then the fraction of the screen taken up with your button can vary in all sorts of uncontrolled ways, if you have a high-density-but-small-sized screen, then your buttons will be overly large.

EDIT: Further to my last edit, maybe I should be more specific about what I want... let us say that I want a square ImageButton that is approximately 10% (I'll accept a variation from 8% to 13%) of the width of the (portrait only) screen ... what size images would I make and what directories would they be in?

EDIT: I'm getting the message that if you have more screen real estate, then the standard thing to do, is to allow the icons to take up a smaller fraction of the screen. Presumably this is because allowing icons to become very large, makes them look rather toy-like, or childish. BUT the thing is, I'm making game apps for children! So this is exactly what I want.

Upvotes: 1

Views: 3964

Answers (8)

Emanuel Moecklin
Emanuel Moecklin

Reputation: 28866

First of all you need to understand the difference between screen density and screen size.

The screen size is the physical size, measured as the screen's diagonal. Android groups all actual screen sizes into four generalized sizes: small, normal, large, and extra large. A phone might have a screen size of 4.9 inch which would be considered normal, both Nexus 7 (the old one from 2012 and the new one from 2013) have a screen size of 7" which is large, the Nexus 10 has a screen size of 10" and that's extra large.

The screen density on the other hand is the quantity of pixels within a physical area of the screen; usually referred to as dpi (dots per inch). For example, a "low" density screen has fewer pixels within a given physical area, compared to a "normal" or "high" density screen. For simplicity, Android groups all actual screen densities into four generalized densities: low, medium, high, and extra high (plus the new xxhdpi). An old Nexus 7 has the same screen size as a new Nexus 7 but the old one has a resolution of 1280x800 which is 216 dpi or hdpi while the new one has a resolution of 1920×1200 pixels which is 323 dpi or xhdpi (more pixels within the same physical area means higher pixel density in dpi).

An image in the drawable folder will have the same physical size on small, normal, large and x-large screens if the screens have the same screen density. Because the screens have different sizes the image will take up a different fraction of the screen. On small screens it will take up a larger part in percentage than on a large screen.

Nothing will change if the same image is in one of the screen size folders (drawable-small, drawable-normal, drawable-large, drawable-xlarge) but you can decide to put a larger version of the image in drawable-xlarge. In that case the image would be larger on a Nexus 10 than on a new Nexus 7 (both have xhdpi pixel density).

If the screens have a different pixel density that same image will look differently though. The image would be half the size on an xhdpi screen compared to an mdpi screen (because the xhdpi screen has approximately double the pixel density):
http://developer.android.com/images/screens_support/density-test-bad.png

In case of an icon you usually want it to have the same size on different screens. That's why e.g. menu icons for mdpi screens are 32x32 and those for xhdpi screens are 64x64 and both are in the appropriate drawable folder (drawable-mdpi and drawable-xhdpi):
http://developer.android.com/images/screens_support/density-test-good.png

Now when do you use the pixel density and when do you use the screen size drawable folders?

Pixel density folders are used if the image should have the same physical size on screens with different screen densities which is usually what you want. If you use the same image for an old and a new Nexus 7 it would have a different size even as the screens have the same physical size and that's not what you want. So using density dependent images is imperative.

Screen size folders are used if you want an image to have a different physical size on small, normal, large and x-large screens. If I have a grid navigation with 6 icons on the main screen and I don't want to make use of the extra screen real estate on larger screens (e.g. by adding more icons), then I would provide a small image for the small screen and a large image for the large screen. You would still have to provide density dependent images on top of the screen size dependent images as explained before (example old Nexus 7 vs. new Nexus 7).

So in theory you would need 16 different resources for the same image (4 screen sizes in 4 screen densities or with the new xxhdpi density even 5 densities -> 20 resources). Now of course no one wants to create that many resources especially if you have a lot of images. One approach is to use the Dashboard as someone has suggested: http://developer.android.com/about/dashboards/index.html#Screens
and pick the most commonly used combinations which are small/ldpi, normal/mdpi, normal/hdpi and normal/xhdpi (81% of all devices). That way you bring down the resources to just 4.
Another approach is to provide resources for either screen size or for screen density (again only 4 resources needed) and then do some scaling in code.

If you have screen density dependent resources then you would use e.g. this https://stackoverflow.com/a/5016350/534471 to scale the images down (never up).

If you have screen size dependent resources then you would use this http://developer.android.com/reference/android/util/DisplayMetrics.html to scale the images down.

There's a nice example for all this here (including source code): https://www.captechconsulting.com/blog/steven-byle/understanding-density-independence-android

Now for you specific problem you could use one generic image in the folder drawable. The size of that image should be so that it won't have to be up-scaled (because that would look ugly). You define the button in the layout like this:

<ImageButton
    android:id="@+id/myButton"
    android:src="@drawable/myDrawable"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="centerCrop"
    android:adjustViewBounds="true"
/>

Together with this piece of code the button scales to 10% of the screen:

Display display = getWindowManager().getDefaultDisplay();
Point screenSize = new Point();
display.getRealSize(screenSize);
int size = Math.min(screenSize.x, screenSize.y);
int buttonSize = Math.round(size * 0.1f);
ImageButton button = (ImageButton) findViewById(R.id.myButton);
button.setMaxWidth(buttonSize);
button.setMaxHeight(buttonSize);

How large should the original image be?
A Nexus 10 has probably the highest screen resolution of all Android devices at the moment. The 1600 pixels will translate to 3200 density independent pixels on its xhdpi display. 10% of 3200 is 320. If you use a 320x320 image then you will get a good result on all existing devices.
There's a catch to this approach though.
320x320 is pretty large (possibly 24/32 bit color depth) and thus you might run into memory issues. If you provide the same resource in the density dependent drawable folders you can lower the memory footprint for hdpi, mdpi and ldpi devices:

  • drawable-xhdpi: 320x320
  • drawable-hdpi: 240x240
  • drawable-mdpi: 160x160
  • drawable-ldpi: 120x120

The screen size drawable folders could be used to further improve this (smaller screens need smaller images) but then you'll have to provide the 16 or 20 resources as mentioned before. In the end it's a trade-off between memory footprint / speed on one side and maintainability / time to create the resources / apk size on the other side.

Upvotes: 11

Eddy
Eddy

Reputation: 589

Let's say you nedd imageButotn 10% of width for different Screens sizes it will be 32 for (320x480) mdpi 48 for(480x800|854) hdpi 64 for(640x1024 (galaxy tab 7")) large-hdpi 72 for(720x1280 (nexus 7)) large-tvdipi 72 for(720x1280 (xperia sp,etc) xhdpi 80 for(800x1280 (motorola xoom 10") xlarge-mdpi 108 for(1080x1920 (xperia z,etc) xxhdpi so u make images at all this sizes and put them in the folders they should be.

Upvotes: 0

124697
124697

Reputation: 21901

This doesn't answer your question exactly. but if you're just looking for generic icons take a look at t IconicDroid library it helped me a lot. You'll be able to resize the icon as much as you want without looking quality and it also saves a lot space so the apk will be smaller. There is a demo of this library on the google Play.

Upvotes: 0

Dage
Dage

Reputation: 236

You could do something like this:

package com.example.test;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.Menu;
import android.widget.ImageButton;

public class MainActivity extends Activity {

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

        //Get ImageButton from XML
        ImageButton ib = (ImageButton) findViewById(R.id.imageButton);
        //Get the screen size
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        //10% of the screen width
        int width = (int) (size.x * 0.1);
        //Get and scale the Bitmap (10% of screen width)
        Bitmap bitmap = getImage(R.drawable.ic_launcher, width, width);
        ib.setImageBitmap(bitmap);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


    public Bitmap getImage (int id, int width, int height) {
        Bitmap bmp = BitmapFactory.decodeResource( getResources(), id );
        Bitmap img = Bitmap.createScaledBitmap( bmp, width, height, true );
        bmp.recycle();
        return img;
    }
}

And the ImageButton:

<ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageButton" />

Upvotes: 0

Shailendra Madda
Shailendra Madda

Reputation: 21561

Go to your project-->Ctrl+n-->Android-->Android Icon Set-->Next-->enter name of icon-->next-->image-->browse-->select image from your PC-->None-->finish. thats it it will automatically creates single image in 4 different sizes in 4 folders named

1.drawable-hdpi 2.drawable-mdpi 3.drawable-xhdpi 4.drawable-xxhdpi

so you can use this image in your application it will take that image based the device screen sizes.

Upvotes: 0

chuck258
chuck258

Reputation: 922

I don't know if I get your question right, but for the relative sizes of the Image, see: http://developer.android.com/design/style/devices-displays.html .

You can use a large enough Image for the biggest Screen you want to support. Then use scaleType="fitCenter" in your Image. Some downsides of this:

And yes: ScaleType.FIT_CENTER is the programmatical equivalent the fitCenter property. In general you can expect every Property in your XML has a getter and setter.

Upvotes: 1

Jin35
Jin35

Reputation: 8612

Usual practice for Android platform is to provide images only for different screen densities, not for screen sizes. If I use tablet I don't want to see big images, I want see more information. So it's better not to increase size of views, but provide different layout for bigger screens.

But if you have some specific reason to provide image 10% of screen width you can use 'drawable' folders with different qualifiers. You are interested in 'Available width', 'Screen size' and 'Screen pixel density' qualifiers. For example provide this images:

  • drawable-sw320dp-mdpi - image 32px width
  • drawable-sw320dp-hdpi - image 48px width
  • drawable-sw320dp-xhdpi - image 64px width
  • drawable-sw400dp-mdpi - image 40px width
  • ... provide images for all devices you want support

Upvotes: 1

Ivo
Ivo

Reputation: 23357

You should at all time create images for all densities. Most images like icons should be fixed height in terms of dp. images of surfaces that aren't fixed height should be 9patch images which are stretchable

More on 9patch here: http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch

Upvotes: 1

Related Questions