Drawables not scaling for missing density buckets, if using drawable references - android

First, some background on what I'm doing. If you are familiar with references in general (simple concept), just skip to section 2, please.
1 The concept of density references
Usually, we use drawables in folders such as drawable-mdpi, drawable-hdpi and so on. Example:
/drawable-mdpi
./figure.png (24x24 pixels)
/drawable-hdpi
./figure.png (36x36 pixels)
[...]
However, another way to achieve (the same?) behavior is defining the same drawable, in different sizes, inside drawable-nodpi, and then referencing each size in values-mdpi, values-hdpi and so on through drawable references. Example:
/drawable-nodpi
./figure_24.png
./figure_36.png
/values-mdpi
./refs.xml
/values-hdpi
./refs.xml
Each refs.xml file should contain lines like this (example for /values-mdpi/refs.xml):
<item name="figure"
type="drawable">#drawable/figure_24</item>
That way, you can reference the same R.drawable.figure as you would without references. I've found this to be helpful when you need to address the same image in different sizes (e.g., using the same image in 24/36/48/72 and 48/72/96/144) without resizing, because you can reference the same image twice (e.g. again, the 48 and 72px images) without replicating images (thus avoiding bloating apk size).
2 Density references don't work if one is missing
As known, Android does not need all bucket densities to display a drawable properly [1]. For example, you may omit drawable-ldpi entirely and it will load and scale those in other drawable-* folders, presenting it for you in the appropriate size in the tested density. In fact, many apps (including from Google) already omit ldpi and nobody notices.
However, I noticed that, when using drawable references (see section 1, above), this behavior changes. If I omit the reference xml file in the density folder, and try to display that drawable in that density, Android will retrieve the highest density drawable variation, but will not resize it according to that density.
Let me give you an example to make it clearer: if, using referenced drawables, I omit values-ldpi/refs.xml, Android will retrieve the drawable from values-xxhdpi (the highest I provide for this arbitrary drawable) and show this in the size corresponding to xxhdpi, and not ldpi, as it should. Therefore, any layouts displayed in a ldpi device will have huge images. See images below:
A) Normal drawables work fine even if LDPI drawable is missing:
A) Referenced drawables don't work if one density reference is missing (I didn't provide an explicit variant in values-ldpi/refs.xml):

Nevermind, I tested in an ldpi emulator right now and it works. So it's one of those bugs that only affect the layout preview pane in the IDE.
Yes, I should have tested in an ldpi emulator before asking. :)

Related

Do I need to use all of drawable, drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-xxhdpi & drawable-xxxhdpi?

I realise that Android will try it's best if it does not find an icon in the required folder but I see someplaces they suggest all of the above and in others they don't include drawable ?
So should I populate drawable as well if all the others are filled with my tab icon images?
If you use a VectorDrawable, you don't need to add a Resource for every density (mdpi, xhdpi etc). VectorDrawable is supported since API 21 (Lollipop) or with Support Library (or AndroidX).
For simple types of images (usually icons), you can avoid creating separate images for each density by using vector graphics. Because vector graphics define the illustration with geometric line paths instead of pixels, they can be drawn at any size without scaling artifacts.
For images (PNG) on the other hand, you must add proper icons for every density because Android will try to scale the images (so they can proportionally occupy same area in all devices). When scaling, the image may become blurred reducing the quality of your UI.
To provide good graphical qualities on devices with different pixel densities, you should provide multiple versions of each bitmap in your app—one for each density bucket, at a corresponding resolution. Otherwise, Android must scale your bitmap so it occupies the same visible space on each screen, resulting in scaling artifacts such as blurring.
You can read more HERE and HERE
EDIT
Maybe, you don't need to duplicate ALL icons. A lot of factors can lead to different experiences such as using wrap_content or a specific dimension to control the icon size or even using a different scaleType in your ImageView. So, maybe, you can start by adding icons for xhdpi or xxhdpi folders only and check your screen in different screen (small display, large displays, low-resolution displays, high-resolution displays etc). Then, you can "duplicate" only the necessary icons... But if your project or APK size is relatively small, don't mind to duplicate the icons.
There's even some online tools to generate the assets for every density from a single PNG such Android Asset Studio website..
If you are adding all resolution drawable icon like :
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxdpi
then you need not to add any extra icons on drawable folder
because all the device resolution covers under the above drawable folders

1080x1920 420dpi screen not accessing from sw420dp

I am creating different values folder for supporting different screen sizes.The following are the folders:
values-sw320dp-hdpi
values-sw320dp-xhdpi
values-sw320dp-xxhdpi
values-sw420dpi
values-sw560dpi
values-sw480dp-hdpi
values-sw480dp-xhdpi
values-sw480dp-xxhdpi
values-sw600dp
values-sw720dp
In the list of devices provided by Android Studio there is 1080x1920 420dpi.It should access dimens values from values-sw420dp.But instead it is accessing from sw320dp-xxhdpi.The layout in 1080x1920 420dpi **looks slightly different from **1080x1920 xxhdpi. Can anyone explain to me why it is not accessing from its own folder?Or could you explain to me the correct way to create a layout so that it support different screen sizes with different densities?I have referred different sites.They are confusing..Please help me!!
I am creating different values folder for supporting different screen sizes.
First, using density qualifiers (e.g., -xhdpi) on resource types other than drawable and mipmap is a serious code smell. Almost assuredly, you are not going to get the results that you expect.
Second, there is no -sw420dpi or -sw560dpi qualifier. You could have -sw420dp or -sw560dp, to say that you want to use these resources for those screen size thresholds. However, such directories would never be used, because of your density qualifiers on directories like values-sw320dp-hdpi.
In the list of devices provided by Android Studio there is 1080x1920 420dpi.It should access dimens values from values-sw420dp
No, it should not.
The smallest width of that screen is 1080px. 1080px, at 420dpi, is 411dp (1080 * 160 / 420). 411 < 420. Hence, anything that is -sw420dp will not qualify.
But instead it is accessing from sw320dp-xxhdpi.
Partially, that is because 411 is lower than 420.
Partially, that is because you are using density qualifiers here, which short-circuit a lot of the "normal" rules for resource selection.
The layout in 1080x1920 420dpi **looks slightly different from **1080x1920 xxhdpi.
Your question has no layouts, so nobody can comment on that.
Can anyone explain to me why it is not accessing from its own folder?
There is no "its own folder".
Or could you explain to me the correct way to create a layout so that it support different screen sizes with different densities?
Use layout resources based on screen size and (perhaps) orientation (e.g., res/layout-sw420dp/)
Use dimen resources measured in sp (for sizing text or things that are dominated by text) or dp (for everything else) in those layout resources (e.g., <dimen name="margin">16dp</dimen>)
Use density qualifiers, and maybe size qualifiers, for drawable and mipmap resources (e.g., res/drawable-hdpi/)
Frequently, that is sufficient.
I have referred different sites.They are confusing
Perhaps consider reading a book.

Differences between scaling images with dpi as opposed to dp

I have all of the dpi drawable directories (are xxhdpi and xxxhdpi even necessary?) consisting of nine-patch bitmaps, the drawable resource file in the drawable directory that retrieves all of the scaled bitmaps, and I set the backgrounds of the Buttons with the drawable resource file... Now, my problem is that I also created "scaled" layout directories in terms of size (small, normal, and etc.), in which I tried to manually change the dp of the buttons as follows:
Here's my xhdpi bitmap:
... But it appears like this on the Nexus 7 virtual emulator (7.0", 1200X1920: xhdpi) in the layout-large directory:
... And when I manually change the dp size to 200 of one of the buttons:
^^^ How do my directories look by the way? ... And why does the button appear like that? ^^^
All of that said, I just don't understand why we need density-based drawable directories (mdpi, hdpi, xhdpi, and etc.) as well as layout resource directories, when we could just simply modify the dp of images in each unique layout regarding the screen's size (small, normal, and etc.).
#dpark14 I basically already answered the question you asked in a your post from yesterday here: Is modifying the dp size as opposed to pixels recommended for various screen sizes?
Perhaps you should have edited your last question to include the code and images above so it could be consolidated.
As I said in my answer (and one of the other comments said):
It is entirely up to you if you want to change the layout width and height (in dp) of an imageButton. There is certainly nothing wrong with setting width and height of an imageButton or any UI element for that matter, in each unique layout resource file for various screens. Did you have specific code you wanted to get feedback about?
Now that you have included some images I can see some of what you have.
You should really take a look at this:
Android Studio drawable folders
And it would benefit you to read through the Android documentation again:
http://developer.android.com/guide/practices/screens_support.html
To summarize a few general ideas:
You don't need a default drawable folder, but you should have the following:
drawable-mdpi (medium) ~160dpi
drawable-hdpi (high) ~240dpi
drawable-xhdpi (extra-high) ~320dpi
drawable-xxhdpi (extra-extra-high) ~480dpi
drawable-xxxhdpi (extra-extra-extra-high) ~640dpi
As the Android documentation says in the link above:
Your application achieves "density independence" when it preserves the physical size (from the user's point of view) of user interface elements when displayed on screens with different densities.
Instead of:
If, for some reason (as it looks like you're having issues with) you've achieved density independence, but your image doesn't fit well, that's when you can start to step in with changes to w/h and res/layout
Also from my previous answer:
As you alluded to: you could create different res/dimens directories for various devices based on "minimums" e.g. w800dp/dimens.xml and then create elements in that specific dimens.xml e.g. values-w411/dimens.xml for width and height that correspond with your images that aren't fitting well when you test your app.
As a first step, perhaps you should try it out. Yes, this takes time, but try a stand-alone test separate from your app first. Just add one image (perhaps the one you are having issues with). See what happens when you load it into different Nexus devices in the emulator. Does the image achieve "density independence" i.e. preserves the physical size across devices? If it does, and there's an issue with its w/h in relation to the confines of a specific device, as I said in my previous answer and now here, create a dimens directory (within a values-... directory) specifically for the problem device and change the layout_width/layout_height for that specific image or view.
For more on specific device w/h: https://design.google.com/devices/

Trick to supply resources to different drawable folders

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

Will drawables in drawable-tvdpi scale down?

If you put drawables in /drawables directory they will be scaled and if you want specific drawables for different densities you need to put them in specific directory (/drawables-hdpi, /drawables-mdpi etc.)
But if I have drawables only in /drawable-tvdpi will they scale down/up automaticly for ither densities?
Yes they'll scale, so if you put a 133 x 133px drawable in the tvdpi folder, it'll be 100px on mdpi, 150px for hdpi, and so on.
There's more information on the Android Developers - Screen Support page, but in general you can get away with just putting drawables in the tvdpi folder.
I believe they will, Android always picks the best available image inside your directories, i.e. if you have an mdpi phone, and two resource types, hdpi and xhdpi, it will try to pick the one immediately above the requested density (hdpi) instead of the bigger one, because it correctly assumes it' going to be enough. Take a look here.
However why not try it for yourself using Bluestacks? It's an Android simulator that runs pretty well. It's still in beta, but has served me well.

Categories

Resources