Providing drawables for different devices - android

Essentially, an application should support various devices. I'm using these guides: mult.screen.supp, screen.stat.
Design for both tablets and handsets on most of the activities is similar. What i'm puzzled about is how to provide drawables for both versions knowing that their density groups provide different resolutions and hence the drawables are not substitutable.
For example, compare xlarge(tablet) - mdpi to normal(handset) - mdpi:
Normal screen, Medium density (160), mdpi: 320x480
Extra Large screen, Medium density (160), mdpi: 1280x800
So, if I create foo.png(50px x 50px) for the first group and then test the same layout
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/foo" />
on the second group, which will lookup for the same image in the mdpi folder, - the image will look tiny.
I have a solution but I'm not sure whether I'm doing it right:
Create attr.xml for each Screen size configuration.
Create <item name="foo" type="drawable">#drawable/h_foo</item> in handset-resources folders, which references image with appropriate for normal(handset) - mdpi resolution h_foo, say 50x50.
Create <item name="foo" type="drawable">#drawable/t_foo</item> in tablet-resources folders, which references image with appropriate for xlarge(tablet) - mdpi resolution t_foo, say 150x150.
Could you elucidate whether this approach is fine and what are other solutions out there ?

It is better when you keep the same resource name and just use different folders to put the actual png:
drawable-mdpi -> used for normal screens
drawable-large-mdpi -> used for large screens
See providing resources for the available configuration qualifiers.

To avoid duplicates I keep all my images in the drawable-nodpi folder, and suffix the file names with a size (e.g. image-small.png, image-medium.png etc). Then I have XML definitions in the device-specific (drawable-normal-mdpi, drawable-large-mdpi) folders for each item. For example:
drawable-normal-mdpi/image.xml:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="#drawable/image-medium" />
drawable-large-mdpi/image.xml:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="#drawable/image-large" />
Note that I saw a comment on here from a Google engineer (can't find it now) that didn't recommend this functionality, but until someone comes up with a better solution (that is compatible with older Android versions) then I'm sticking with it.

Related

app's UI is not proper in a 220 dpi screen

hi I'm new in android developing and it's my first app.
I have made these folders in address : app\src\main\res for supporting multiple phone and tablet screens and put proper dimens.xml files in them.
values-ldpi
values-mdpi
values-hdpi
values-xhdpi
values-xxhdpi
values-xxxhdpi
values-sw600dp
values-sw768dp
values-sw800dp
first of all, are they complete or am I missing some screen sizes?
second, I've tested the app on several devices and it's working fine and has proper user interface in all phones but on the Galaxy Grand Prime which has a 5 inch 540 x 960 pixels display that means 220 dpi. this phone using hdpi dimens but UI is a bit messy.
The following pictures may make my point better :
Proper UI , as it is shown in other devices
VS
UI in galaxy grand prime 220 dpi display
as UI is completely OK in other devices, I thought I should make a specific dimens.xml file for that kind of dpi, so I made values-sw220dp. but after that other phones used this dimens instead of hdpi dimens and problem got worse because UI was fine in the galaxy phone and was not proper in other hdpi displays. and now I don't know what should I do.
can anyone help me in this issue?
at last sorry because of flaws in my english , as you can guess I'm not a native.
are they complete or i'm missing some screen sizes?
If you read the guides which I mentioned at the end of my answer you will find that there are very many possibilities of defining resources folders. I think nobody will want to implement all of them.
Usually you look at your app and then decide on maybe three or four screen sizes you want to support. I think "sw220dp" is important, if only to show a message that your app needs more space :-).
So there could well be three to five layout folders (sw220dp, sw320dp, maybe sw480dp, sw600dp, maybe sw820dp). If you need orientation-dependent layouts, then the number will be twice that much. (Why ? That's explained very well in the guides linked below)
You already know that there are different types of resources. Some of them do not depend on the screen resolution (e.g. layout files), some do (drawable resources).
So first of all you decide which screen sizes you want to support. Let's say they are "phone", "tablet" and "220dp". You create three layout files by the same name "my_activity.xml" and put them in three folders
for the really small window: res/layout-sw220dp
for the mobile phone: res/layout-sw320dp
for the tablet: res/layout-sw600dp
By the way, "sw" stands for smallest width which is the minimum length of the screen, no matter what the orientation is currently.
Now let's assume you have created three different layout files and all of them contain an ImageView like this:
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="#drawable/my_picture" />
This is where the screen resolution comes into play: 24dp is a size value in "density-independent pixels". It will be resolved depending on the screen resolution of the device. So you need different versions of my_picture.png, and for this you need different folders for drawables. They are named after the different categories for screen resolution so the runtime knows which png file to pick:
res/drawable/ldpi (although I read somewhere you can skip that because the pictures will be scaled down from hdpi nicely)
res/drawable (here go the resources for res/drawable-mdpi as well as every drawable resource for which resolution does not matter, e.g. drawables defined via xml files)
res/drawable-hdpi
res/drawable-xhdpi
res/drawable-xxhdpi
res/drawable-xxxhdpi
Helpful links:
Providing Resources
Supporting Multiple Screens

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/

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

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. :)

Android supporting multiple screens with Images

I read a lot about supporting multiple screens problems in Android, but I didn't solve mines yet. If I understood well, there are at least 2 ways to show images on different screens and to make it look normal. First, to make many images (xhdpi, hdpi, mdpi, ldpi). Second, is to create layouts(big, medium, small and etc.) My question is: which method is better? Now, my problem. I took first method, create my image in different sizes and copied to folders according to image's size. I used DEVS BITMAP app to get size, which I want my image to look like for different screens. I'm getting perfect view when I look on the 7' screen, but the view gets terrible on 3' screen. I copied this code to my Manifest:
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
I think it isn't necessary, but I wanted to be sure I am doing everything good. Could anyone answer my question and solve my problem? I would appreciate your help! ;)
Create a new Project.
There is a layout folder ,values-sw600dp,values-dw720dp-land. In both these folders, there is a dimens.xml file. What is written in it is this :-
<resources>
<!--
Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw720dp devices (`e.g. 10" tablets)` in landscape here.
-->
<dimen name="activity_horizontal_margin">128dp</dimen>
That mean folders with sw-720 dp are for 10 inch devices, similar 600dp are for 7 inch devices and default layout folders vary from 3 to 5 inch device.
layout-sw600dp -> This folder will have xml in PORTRAIL Orientation for 7 inch devices
layout-sw600dp-land -> This folder will have xml in LANDSCAPE Orientation for 7 inch devices. When you rotate your device, view will be formed from this folder
Based on the dpi/resoulution of your devices, you can create unlimited number of layout folders.
Similarly, there are folders for images called drawable ->hdpi ldpi mdpi xhdpi xxhdpi. Based on the resolution of devices, images are picked from their respective category.
xxhdpi will contain images with the highest resolution. So try to download big resolution images and downsize them and put them in the other folders.
Now how to know which device will take which image ? See the image below :-
See the drop down. It contains a list of devices with their resolutions and image type -hdpi ldpi mdpi xhdpi xxhdpi. Moreover, you can GOOGLE for the devices and their resolutions and dpi's.
So whatever app you are making for a device, choose that device and look at its resolution and see whether it is hdpi or ldpi etc. Accordingly, put the images and layouts.
This is my understanding. I create my layouts with this understanding. I hope you got a clear picture
For Multiple Screen Support
Add Different size of images to
drawable-ldpi/
drawable-mdpi/
drawable-hdpi/
drawable-xhdpi/
drawable-xxhdpi/
Suppose you have Imageview in layout folder
<ImageView
android:layout_width="#dimen/horizontal_len"
android:layout_height="#dimen/vertical_len" />
Do the following values
values/dimens.xml (Normal mobile)
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="horizontal_len">16dp</dimen>
<dimen name="vertical_len">16dp</dimen>
values-large/dimens.xml (7 inch)
<dimen name="horizontal_len">20dp</dimen>
<dimen name="vertical_len">20dp</dimen>
values-xlarge/dimens. xml (10 inch)
<dimen name="horizontal_len">22dp</dimen>
<dimen name="vertical_len">22dp</dimen>
So you have to try like this.

How can I alias an android bitmap to a drawable from another size (drawable-large-mdpi aliases to drawable-hdpi)

I'm working on adding support for tablet sized screens to my apps. I already have images in drawable-mdpi and drawable-hdpi for different density screens. My problem is with tablets like the Galaxy 7" which is a "large" screen but is still medium density. Part of my layout has 5 buttons across the width of the screen which are evenly spaced. On the large screen with mdpi graphics though the images are very small with tons of whitespace between them.
I would like to use larger graphics for the large layout to make them look appropriate as well as take advantage of the screen real estate. I have some double sized graphics in my hdpi directory that would work perfectly. As a test, I've copied all of the images from /res/drawable-hdpi into /res/drawable-large-mdpi and everything looked exactly as I want.
However, I don't want to bloat the size of my app by coping all of those images. I would like to just create aliases for each of them so that when /res/drawable-large-mdpi/button_0 is requested, it will actually use /res/drawable-hdpi/button_0 instead.
I've tried creating an xml bitmap but I don't know how to reference a drawable from a specific directory. Any help?
Contents of /res/drawable-large-mdpi/button_0.xml:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable-hdpi/button_0" />
The error I get with the above is:
error: Error: No resource found that matches the given name (at 'src' with value '#drawable-hdpi/button_0_highlighted').
Move your button resource into the drawable-nodpi folder and rename it to button_0_hdpi.xml.
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/button_0" />
When using an XML alias you can not specify the qualifier. You had #drawable-hdpi and it needs to be just #drawable. You probably also need to make a second XML alias in the original location of you button bitmap.
Here is a good article on the method http://blog.evendanan.net/2011/03/Android-resources-and-device-fragmentation
this page talks about the different modifiers you can use on resource folders. It seems to indicate that the order of precedence is such that screen size(small, med, large, xlarge) is higher than density(ldpi, mdpi, hdpi). I would think that this means if you renamed your drawables-hdpi folder to drawables-large-hdpi even though the Galaxy tab has a medium density it will still use the drawables from this folder because it has a large screen.
Edit: I just tested this out, it does solve your problem one way. They images inside the drawables-large-hdpi folder to show up on the Galaxy tab when running the app. But unfortunately adding the large qualifier makes it so they don't show up on medium sized screens with hdpi densities. Its looking like you might have to make separate folders and have 2 copies of your large resources if you want to get this functionality =(.

Categories

Resources