I am wondering what your thoughts are on which is the better strategy when designing UI for android devices.
Which do you preffer:
Setting the size of elements in the XML files, for each denisty (and size when needed), using only one set of images (xxhdpi images) which will scale down when needed.
Pros - smaller apps (less resources)
Less work on images for UI people.
Cons - more work on XML files (a whole lot sometimes)
Create images for each denisty (and size if neede) using Wrap_content most of the time.
Pros - Only one set of XML layout files.
Cons - more images and larger sized apk.
more work on images for UI people.
What other approaches are you using?
Thanks!
I think you are misunderstanding what Android is doing when it scales images that you do not provide. The Android docs state:
By default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.
All this means is that if you do not provide alternate density versions of images, Android will fill in the missing ones (created and the correct proportional size) using the ones you have provided, but at the cost of some quality of the image, since Android is not going to scale an image as well as say Photoshop. If you are concerned with application size, you can consider if the loss of image quality from omitting certain density versions is an acceptable tradeoff in order to make your .apk smaller.
So, #1 and #2 can both use wrap_content, and neither has to set the size of an image manually, unless the image needs to be larger or smaller than the original size (which in that case you should just create the image at the right size). #1 also does not and should not require more layout work. And for #2, saving an image at several sizes is not very much extra work at all.
I personally follow these rules:
Create images for every density (except ldpi / tvdpi - too few devices, I'm ok with the image quality loss on them).
Use wrap_content and match_parent as needed with images.
Only use dp for images downloaded at runtime, where size cannot be guaranteed.
my choice is a mixed one. I create differet images for those which are complex and has a chance of being abnormal for automatic compression. But for usual images I only used the first approach.
Related
i just released my app on android and have problems with customers with high density displays.
i added a debug thing to see what's going in, here is one sample output
Device: Nexus 10 Android version: 4.2.2
DisplayMetrics{density=2.0, width=2560, height=1504, scaledDensity=2.0, xdpi=298.275, ydpi=298.823}
MainView w=1900 h=1342
mDrumKitMode=BIG
KitView w=640 h=1266 x=1920.0 y=0.0
the main view is the music notation area on the left of the screen shot, its 1900 wide (MainView w=1900 h=1342) the drum kit is a bitmap that is 640w and 640 high. somehow, the display is scaling it to be full height of the parent, (KitView w=640 h=1266 x=1920.0 y=0.0). this doesn't happen on displays where density=1.0.
i have no way to test this since i can't get the emulator work on big displays for some reason and i don't have a high density tablet.
does anyone have an idea what could be going on? thanks
and here's another customer with a similar problem
Device: A700 Android version: 4.1.1
DisplayMetrics{density=1.5, width=1920, height=1128, scaledDensity=1.5, xdpi=224.73732, ydpi=224.11765}
MainView w=1260 h=1044
mDrumKitMode=BIG
KitView w=640 h=968 x=1280.0 y=0.0
i think its the scaledDensity=1.5 parameter, maybe i need to do something to disable automatic image scaling, i.e. set scaledDensity=1?
i should add that the entire application is based on exact pixel positions, both for the music notation display and the drum kit display which overlays images on top of the base drum kit image (you can see the drum pedals are in the wrong place on this image too). i don't want automatic scaling as i handle scaling inside the app for different display sizes and user preferences.
i should also add that all my drum kit images are in drawable-mdpi and all the other dpis are empty. this is because i scale images programmatically based on screen size and user preference BUT i think maybe the problem is a need to put some images in xhdpi? i guess i can do that but it will be a lot of work.
PS, i guess i found my answer here http://developer.android.com/guide/practices/screens_support.html
Provide different bitmap drawables for different screen densities
By default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.
i wonder if simply copying all the -mdpi images to -xhdpi will work?
If you intend for this app to be used across devices you have no choice but to put in images for all the various density folders that exist (xhdpi,xxhdpi, hdpi, mdpi). It's also worth considering that you may want to change the actual layouts you include, to offer different ones for different devices.
Consult the documentation for how to handle this.
http://developer.android.com/guide/practices/screens_support.html
If that creates an apk that's too heavy (I have no idea how many images you have) then you can go the other way and specify a no scaling drawable folder which will just use the images in their native density across devices. It's definitely wrong to use ONLY mdpi unless you intend to support only mdpi devices.
Everytime, when I supply resource to drawable folder, here is what I did
drawable-xhdpi (96x96 px)
drawable-hdpi (72x72 px)
drawable-mdpi (48x48 px)
drawable-ldpi (36x36 px)
Most of the time, I merely use GIMP to perform dummy scale down from the largest size image from drawable-xhdpi. I do not perform any further pixel editing on the scaled down image.
Recently, I realize, if I only supply 1 highest resolution image, Android system will internally perform image size scale down.
drawable-xhdpi (96x96 px)
drawable-hdpi (empty)
drawable-mdpi (empty)
drawable-ldpi (empty)
I tested on 2 devices. It works for me. I was wondering is this a good technique to avoid cumbersome work to supply so many different size images? Any side effect on this technique?
I was wondering is this a good technique to avoid cumbersome work to
supply so many different size images? Any side effect on this
technique?
I imagine there are (at least) two:
This may not always work with 9-patches, especially if the stretchable area is defined by one or more single pixels. For example, if you would provide such a 9patch as xhdpi drawable, then on an mdpi device that single pixel will effectively be 'halved' and thus either disappear completely or blended with the surrounding transparent pixels. The latter is generally true for any upscale/downscale operation, so it's quite likely that your 9patch will not appear as intended.
Larger images will simply take up more space in memory. Especially on low(er)-end devices, with a limited amount of internal memory and a reasonably strict heap space limit, you're likely to run out of memory fast when loading images way larger than required for displaying.
Regarding your comment: it's fairly easy to come up with a sample 9patch that will not visually look as intended across all different screen densities if you supply it only as xhdpi resource. Consider the following 9patch:
Enlarged snapshot for the sake of visibility:
Obviously, the idea is that when this 9patch gets stretched, the result is a 1-pixel thick horizontal blue line. Now, drop this 9patch in just the xhdpi folder and compare the results on xhdpi vs. mdpi:
Clearly, the mdpi device has scaled down the 9patch from the xhdpi folder and the result doesn't look like intended.
Anyways, my point is that in a lot of cases not supplying 9patches for every density bucket may end up looking fine. Just be aware of the fact that there are definitely scenarios out there for which it may not give the desired result. Also, take into consideration the memory argument.
The technique you are using will work on fewer number of devices..
Because in market there are a lot of phones with different resolutions and different sizes.
In some low resolution devices whose screen size in smaller,the UI will not look proper...
Now take an example that you are using a background image for splash screen whose resolution is 720*1280(xhdpi) and you have put it in Xhdpi drawable folder than when you view this drawable in low end device like Samsung euopa or HTC wildfire the image would look squeezed type.
there would be a lot other situation where you would be required to use different set of images....
If the technique mentioned by you would work in all phones then why would had Android developed different folder for different set of images.... :P
What is the size of the background images (png files)? How do I determine the size of the image? (I would like to cover the entire relative layout, thus the entire screen)
Do I need to have several png files, all with the same image but with different sizes to be supported on all screens? (3.7 inch, 4.2 inch, tablet size and etc...)
Can anyone help?
I though of having 1 image and then streching it according to the screen size retrievd from the device system, is this the correct method?
you can use fill parent but for accurate info
use http://developer.android.com/guide/topics/resources/providing-resources.html#BestMatch
it will help you to provide resources it is the developers site -- it has info on providing resourses you can also see supporting multiple screens for better understanding
I know about supporting multiple screens in Android and I use it in my app. But supporting different screen sizes and DPI makes your application size large. We all know about the 50mb file size limit in Google Play right? So, is it possible to create a folder like the following?
\layout-small-160
\layout-normal-240
If that is not possible do any one here knows how to support multiple screen sizes and its DPI's without using too much image to make my application size smaller?
I only give my suggestion and you can try it.
By default, we have three drawable folder drawable-ldpi(120), drawable-mdpi(160), drawable-hdpi(240).
When the App need image, Android will find the image according to the screen destiny. Obviously, the image in drawable-ldpi folder is fit if the app running on phone which have a low destiny.
But if there is no image in drawable-ldpi folder. Android will find if there is image in drawable-hdpi. If it exists, android will scale the image(0.5) and show it.
So you don't need to prepare images for every destiny. You only need to prepare the image for hdpi scrren. And for some individual images which demand accurate size, you need to prepare for the three destiny.
You could download some famous APK and extract them.Then enter the res folder to check how the author did.
Sorry for my poor English.
From Supporting Multiple Screens article of Android documentation:
To optimize your application's UI for the different screen sizes and densities, you can provide alternative resources for any of the generalized sizes and densities. Typically, you should provide alternative layouts for some of the different screen sizes and alternative bitmap images for different screen densities. At runtime, the system uses the appropriate resources for your application, based on the generalized size or density of the current device screen.
Therefore, yes it is possible to create folders for different layouts as you mentioned in your question. The following is a good practice of having your resources folder organized for different screen sizes and different bitmap drawables:
res/layout/my_layout.xml // layout for normal screen size ("default")
res/layout-small/my_layout.xml // layout for small screen size
res/layout-large/my_layout.xml // layout for large screen size
res/layout-xlarge/my_layout.xml // layout for extra large screen size
res/layout-xlarge-land/my_layout.xml // layout for extra large in landscape orientation
res/drawable-mdpi/my_icon.png // bitmap for medium density
res/drawable-hdpi/my_icon.png // bitmap for high density
res/drawable-xhdpi/my_icon.png // bitmap for extra high density
Yet, you do not need to provide alternative resources for every combination of screen size and density. The system provides robust compatibility features that can handle most of the work of rendering your application on any device screen, if you develop your application following the instructions described here.
2 suggestions:
Resize the images to be exactly the size you need. Use proper compression (use a professional application to edit the images, like photoshop, that optimize the image and compress it well).
Put part of the images on an external server and download all on the first use. Downloading the images from the server has the advantage that you know the device size, so you can download only the relevant sizes.
Case close.. It is posible to create a folder that has two modifier..
like this
layout-normal-hdpi ---- this will only set the view from specific phone that has 240 dpi and normal screen
thanks for all who commented and give an idea here..
I have images that need to scale to the screen's size. The images will also have text in it that needs to be translated to a second language. So there will be two versions of each image to start, one for each language.
Google recommends having an image resource per density. So I'd take my two images and multiply them by four: xhdpi, hdpi, mdpi, and ldpi. But then Google say to have different image resource for different screen sizes. This multiplies my images by four again: xlarge, large, normal, and small. I don't want to create 32 copies of every image!
I'm wondering if there is anything wrong with making the images for xlarge screens and xhdpi densities only. IE – Best quality. Let Android scale down the images for lower densities per its standards for dp units. And when I draw on smaller screens, I could use the Canvas class to scale down further. I could cache the resulting scaled Bitmap object for use every time it needs to redraw the bitmap to avoid expensive scaling computations running over and over.
Is there any drawback to doing this? Or is there a better way to avoid making so many copies of the same image?
There will be a performance penalty in downscaling large images on smaller (low-end) devices. Whether this will be noticeable depends on the number of images you have to show.
The same holds, mutatis mutandis, for memory.
I create bitmaps only for the highest xhdpi pixel density, and then test on other screen types.
If a bitmap looks bad on some lower-density screen, I remake it specifically for that density. And this happens quite rarely...
Also, making special bitmaps for different screen sizes (small/xlarge) is not needed - just make your ImageView-s smaller/larger - image scaling is not a slow operation, so in most cases you don't need to worry about it either (unless your bitmaps cover the whole screen).