I have an Android app with 4 versions of the same image, in each of these folders:
drawable-ldpi/
drawable-mdpi/
drawable-hdpi/
drawable-xhdpi/
The only difference between the images is the size, I simply took the original large image and scaled it down according to the formula:
120dp lpdi, 1 dp=0.75 px
160dp mpdi, 1 dp=1 px
240dp hdpi, 1 dp=1.5 px
320dp xhpdi, 1 dp=2 px
The problem is I intend to have over 100 images, so to reduce the file size can't I just put the xhdpi versions in the drawables/ folder instead of having 4 versions of each image, then Android can scale the image as required? What is the disadvantage of doing it this way? Is it simply a trade off between performance and file size?
You can just put the xhdpi versions in the drawable resources. Then in your layout/xml files specify the images dimensions in dp. Android will downscale your images accordingly. As long as you are downscaling the drawable resources quality of the image wont change.
having only the xhdpi resource will degrade A LOT your app performance. Plus on low-range devices (small screens and small memory) it's very likely that the VM will run out of memory and crash whilst processing those large bitmaps.
You can develop everything on your high end device and use a simple photoshop automation to create the other resources but it's better to have a bigger APK than your app not working on mid and low range devices.
Another option might be to export several APK (one for each screen type) and use the manifest to specify which screen sizes it does support and let the market filter the right APK to the right device.
You can. The disadvantage may be slightly worse image quality: consider for hdpi display you need to scale 240/320 times, that is, 0.75, or to speak e.g. in 1D pixel line you make up 3 target pixels out of 4 source pixels. Most of the time it will look very good, but I imagine some pixel art may be an exception. I guess this may be slower as well, and use more memory than it could, but I didn't measure that so I can't tell for sure.
P.S. I'm using this method (providing xhdpi resources only) myself too.
Related
I have read on this forum that the answer is to split the image in different resolutions and put it in different folders and the other way is to put the image in one folder without splitting it up so that android doesn't resize it.
My question is in which folder exactly do we put it on so it doesn't resize itself and shows as it is?
My res folder looks like this
Based on your updated question with the image and the clarity.
You are asking how to avoid scaling. You can either use the drawable directory or the drawable-nodpi to avoid prescaling. Either one will work for you.
I made a document on this once for the UI team I was working with, so this document is a little specific to their request and that app, but it might help you.
https://drive.google.com/file/d/1gJjT-F5AU57TCAr5I18l0jAvNG5-vLUb/view?usp=sharing
For vector drawables just use "drawable" standard directory. Make sure you are not violating any of the unsupported tags such as gradients and linear tags or you will have issues.
Next the -24 -26, etc.. folders are used for version specific. For example, let's say you have one type of image for pre 24 Android, but a different type for post 24, you can use -24 for the post image, and all others will check standard folder for it. This sometimes happens when you use something bleeding edge that isn't supported back far enough for your app's minimum SDK. You are not likely to use this for images, I can't even think of a problem where this would arise in the image buckets, but it's there all the same.
For deciding what resolution you need for each bucket, there are a couple of options here. First you could simply do the math. Decide how many inches you want it to take up and determine how many pixels are needed to accomodate that size and label that MDPI, than scale from there using the multipliers. Another less mathematical solution would be to open a preview on Android select an MDPI device and start playing with width = 100px height = 100px and adjust until you like the size. Write that down, it is MDPI, and begin your scaling from there.
As for a rough estimate of pixels to size, you can see what an app icon looks like and see what Android uses for that below.
So even though each bucket has a different pixel by pixel resolution, they will be identical sized and pixels per inch resolution on all devices due to bucket placement.
Hopefully that all makes sense.
--I'll leave the below from the original answer in case it helps someone--
You may have gotten some bad information.
https://developer.android.com/training/multiscreen/screendensities
Android is a widely dispersed resolution and size market.
In order to accommodate this they allow for DP and Buckets.
There are buckets for languages, screensizes, orientation, and resolutions.
You are looking for resolution support.
drawable-ldpi -.75 multiplier on size (1dp = .75px)
drawable-mdpi -baseline 1dp = 1px
drawable-hdpi -1.5x multiplier on size (1dp = 1.5px
drawable-xhdpi -2x multiplier on size (1dp = 2px
drawable-xxhdpi -3x multiplier on size (1dp = 3px
drawable-xxxhdpi -4x mulipvlier on size (1dp = 4px
each bucket has a multiplier associated to help the image look the same approximate size on each device. So even though it is 1 inch by 1 inch on one mdpi phone with your 100px x 100px image (pseudo size, don't calculate it ;)
it will need to be 150px x 150px on the hdpi to have the same quality and resolution of pixels per inch.
Now if you put all your images in the drawable bucket. Android will just ignore the scaling of these and you end up with varying space consumption depending on the device which will be very inconsistent on how much space it takes up on each type of phone.
If you put all your images in the correct folder you will at least have better quality. For example, let's say you have maybe 750px x 750px image that is meant to fill up a 1 inch area. You would be better suited to put it in the XXHDPI folder or XXXHDPI folder so Android knows to scale it DOWN rather than UP. This will give you better resolution for each device resolution that it scales for.
However, this is still poor practice. You are relying on Android operating system which can be very slow and weak on many cheap devices to do your scaling for you. I would recommend using GIMP and scaling to each multiplier on your own, then putting it into the respective resolution buckets.
This way Android decides based on the device which bucket resolution image it needs which decreases the amount of scaling exponentially.
Now, if you have Vector Graphics that you have imported, those will end up in the drawable folder which tells Android to ignore the resolution, and just draw these as vector graphics. This is the best option in my opinion as you only need one set of images per image. Although, Vector graphics aren't quite as fast at loading as a JPG or PNG, but it keeps your package size down quite a bit and development maintenance is so much nicer.
Hope that helps.
Happy Coding.
I making an app for tablets. and want to use a PNG file for some of the buttons. What size the button must be? Based on Android size it should be at least 48dp x 48dp and with converters 48dp is different in different sizes of android devices. This is a calculator: Link
ldpi # 48.00dp = 36.00px
mdpi # 48.00dp = 48.00px
hdpi # 48.00dp = 72.00px
xhdpi # 48.00dp = 96.00px
So Should I make 4 different files for my png files with top pixels ? for example a version with 36px x 36px for the ldpi folder? or just make the biggest size like xhdpi (96px)?
Thanks in advance.
You CAN just make one large button size and get away with it, but thats not best practice.. You should have different sized images for different resolutions.
From Android:
Although the system performs scaling and resizing to make your application work on different screens, you should make the effort to optimize your application for different screen sizes and densities. In doing so, you maximize the user experience for all devices and your users believe that your application was actually designed for their devices—rather than simply stretched to fit the screen on their devices.
More info on supporting different devices and best practices.
Android Practices
Ya. Better Use 9 patch Images as the background for the buttons. So it will expand/ behave according screen size . Check this Link .
I just use the highest resolution and let Android scale it down. Doing it this way makes the download (file) size much, much smaller than having a different image for each resolution. And the quality as it's scaled down is no worse than it would be if you scaled it down yourself in MS Paint.
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
Last two questions stayed unanswered, I hope "third one's the charm" works :)
I want application that is HDPI use those drawables in folder "drawable-xhdpi" and LDPI devices those in "drawable-mdpi". So I don't have to duplicate same images. Is this possible?
Yes, Android scales drawables, selecting the drawable that will produce the best result. But not all scaling combinations work that well. Downscaling to MDPI can produce noticeably poor results. XHDPI to HDPI generally produces pretty good results. But given that the overwhelming majority of devices these days are HDPI, it's probably worthwhile to have HDPI resources. HDPI to XHDPI scaling is not terrible. Some 1280x720 devices uses XHDPI resource. These generally look ok. Google TV uses XHDPI as well. On a huge screen, scaling errors are visible.
LDPI devices are -- for all practical purposes -- non-existent now.
True that generating scaled resources is an enormous PITA. But, in my opinion, you really need to do MDPI and HDPI. And once you've got that unpleasant workflow down, it doesn't require a lot of extra work to generate XHDPI. For what it's worth, if your artwork is in vector format, the vast majority of resources don't need tweaking for specific resolutions. There doesn't seem to be any compelling need to pixel-align edges of square objects, for example. Usually it's only interior features in complex icons and artwork that benefit from some amount of pixel-pushing.
It's pretty clear that XHDPI is going to be come more and more common. Trust me, you don't want to go back and re-do all your artwork in XHDPI after the fact. My advice: if you intend to still be shipping your app a year from now, suck it up, and do the nasty as you go, while it's still relatively easy.
In my experience, if you place an image in just some of the drawable folders, but not all, the OS will choose the "best" image for the device that you are using, even if it is not exactly the perfect fit. For example, if you put an image called arrow.png ONLY in the drawable-hdpi folder, all devices will use that image for the arrow drawable, and scale it down or up appropriately, stretching or shrinking the image.
That being said, you should be able to accomplish what you want by simply putting your image in the right folders and allowing the devices to choose the correct one. For example, if you were trying to accomplish your task with only one image, arrow.png:
drawable-xhdpi/ -> arrow.png
drawable-hdpi/ -> empty
drawable-mdpi/ -> arrow.png
drawable-ldpi/ -> empty
drawable/ -> empty
If you use the app on an ldpi device, the device will use the mdpi image, as you wanted, because it is closest to the correct resolution. On the hdpi phone, it will use the xhdpi image, because it is again the closest to the correct resolution.
Yes. Android automatically downscales/upscales resources that it cannot find. If you were to only put resources in the XHDPI folder it would just work, Android would take care of resizing them to work in all the other densities.
We should add this code in MainActivity class and copy image to dhpi folder with ic_launcher, ic_launcher2, ic_launcher3 and ic_1 is image name, we can change size: width and height
int array_image[]={R.drawable.ic_launcher,
R.drawable.ic_launcher2,
R.drawable.ic_launcher3,
R.drawable.ic_1
}