I'm struggling with a pretty trivial task in the Android "multiple-screen sizes" domain.
What I'm trying to achieve
A layout matching the screen width, with a nine-patch background which resizes (only horizontally, since there is always enough vertical space). Here is a dummy image:
My goal is, depending on the screen resolution, to display the image at the highest resolution possible, by using a set of different sizes, eg. 320x45, 480x67, 600x87, 720x101, without any down-scaling. I'm hoping for a non-programmatic solution.
An example with the above mentioned image sizes would be:
Issue
The whole Android resource allocation revolves around dp
s (density-independent pixels), when in fact I want to display an image based on the actual available pixels.
If I allocate the 480x67 image to res/drawable-mdpi and a 600x87 to res/drawable-hdpi, then image would display correctly on a 5.4" display of 480x800, i.e. mdpi display. However, a 4" 480x800 displays qualifies as hdpi and the system would appoint the 600x87 image, which won't fit the screen.
I tried the smallestWidth
parameter as described in the online guide, but that yields strange results. For instance, a 3.7" 480 x 800 display (hdpi) uses my drawable-sw320dp image, although there is a drawable-sw480dp resource available too.
Thanks in advance!
I believe that by combining density and screen size resource qualifiers you can achieve a close to optimal behavior.
Lets assume this kind of resource folders structure:
drawable-normal-hdpi
- A normal
size dictates minimum width of
320dp. hdpi
dictates 1.5X dp to pixel multiplier. So the minimum px
width of the normal hdpi
bucket is 480px. We put here a 480px wide
image.drawable-normal-xhdpi
- Again size dictates 320dp but this time
with 2X multiplier. So we use a 640px wide image.drawable-xlarge-mdpi
- Size means at least 720dp. mdpi
multiplier
is 1X, so we use a 720px wide image.Now lets look at some devices to see how they fall in with those buckets:
normal hdpi
. Actual px width: 480px. The image fits
perfectly.normal xhdpi
. We could fit a 720px image, so the
640px image we use isn't optimal - but it's very close.xlarge mdpi
. We could fit 800px, our image
is 720px. Again not ideal but close enough.Worst case scenario: image used could have 5-10% better quality. Best case: perfect fit.
The main down side of this method is that you need to provide a lot of resources and folders to account for all the permutations of sizes and densities (even worse if you need to combine that with more qualifiers for locale, orientation and so on). However, as far as my Android understanding goes I don't think you can achieve something better than this without coding.
A remark regarding smallestWidth
: Your example for the weird behavior is actually the expected behavior.
hdpi multiplier is 1.5 - So a 480px wide hdpi display is exactly 320dp wide. This makes the drawable-sw320dp the right choice, as documented. I'm not sure if you can combine the smallestWidth
qualifier with the dpi qualifier. If it's possible you might get more accurate results than just size modifiers. But this would mean a lot more permutations for a 5% increase in image quality. Probably not worth it.