Android multiple screen size and avoid duplicating images - android

I have an app that displays a bitmap in a TextView as a "drawableTop":
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawableTop="#drawable/bitmap"
android:gravity="center"
android:text="#string/text" />
The bitmap comes from a PNG file in the res/drawable folder, let's call it bitmap.png.
I need to support multiple screen sizes and densities, and want to find the cheapest way (in term of how many PNG files I need to have in res/* folders) to do it.
Various densities: Phones only
I've come to the conclusion that it's enough to have the bitmap.png in res/drawable-xhdpi folder. When being displayed on phones with high density, it will be displayed as is, while on phones will lower density, it will be scaled down automatically.
In other words, no need for having lower resolution versions of the bitmap.png in res/drawable-hdpi, res/drawable-mdpi etc.
Basically only one version of the PNG file is enough for all phones.
Various densities: Tablets as well
Now, the problem arises if I want to support as well tablets: large and xlarge screens.
On tablets, I want the aspect ratio of the icon to be the same as it was on phones: If the bitmap took 1/4 of the screen on phones, I want it to take 1/4 of the screen on tablets. I cannot reuse the same PNG file as before or it would look too small since the tablet just has more pixels... So for tablets I need a higher res PNG. And this applies both to large screen and xlarge screens.
Which results in the need for 3 folders, and 3 versions of the PNG:
1: res/drawable-xhdpi/bitmap.png
2: res/drawable-large-xhdpi/bitmap.png
3: res/drawable-xlarge-xhdpi/bitmap.png
But 1 and 2 are basically lower res versions of 3.
So is there an easy way to have a single folder not 3?

If you want to keep only one image for all resolutions, why not keep in res/drawable and res/drawable-land folders?

If you are talking about cheapest way to do this (not adding more than one image in drawables), then use 9-Patch Images. If you dont know about it, then have a look n learn usage here:
http://www.androiddom.com/2011/05/android-9-patch-image-tutorial.html
http://www.androiddom.com/2011/05/creating-custom-drawn-button.html

Judging from your question, you don't need different orientated images for tablet or phone.
If you want the image to take 1/4 size on both devices, then define your image in your xml as using d(i)p. This will scale the image to the same size on all devices.
d(i)p is scaled relative to 640x480 (or 480x640 resolution for portrait orientation).
So you can calculate different combinations of resolutions to cover 1/4 screen space, such as 320x240 or 240x320
If you want control over the scaling of your image, I would suggest putting the image in an ImageView. This will allow you to use the android:scaleType property to scale your image how you wish.
You can set the background of your TextView to be transparent, and have the ImageView below it contained within a relativeLayout of your desired size to achieve the same effect as you current have, like so:
<RelativeLayout
android:layout_width="320dp"
android:layout_height="240dp"
>
<!-- Images at the top of the xml are drawn on the bottom! -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:src="#drawable/bitmap"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/text"
/>
</RelativeLayout>
Also consider using alias resources.
This will allow you to define an xml file which will act as if it's the real PNG image (and is referenced as such in R.drawable. , but is actually a reference to another image.
From the linked Google documentation:
To create an alias to an existing drawable, use the element.
For example:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/icon_ca" />
If you save this file as icon.xml (in an alternative resource
directory, such as res/drawable-en-rCA/), it is compiled into a
resource that you can reference as R.drawable.icon, but is actually an
alias for the R.drawable.icon_ca resource (which is saved in
res/drawable/).

Related

Using just one (high density) image to scale to width in a scrollview for all devices

I'm developing a kind of a instructions app. It uses fragments with ScrollvView, vertical LinearLayout and some TextViews / ImageViews in it to explain how a product works.
The images are just simple vector graphics which I save as png due to the lack of vector image support on Android. Here's an example:
The images are always filling the the screen using android:scaleType="fitXY" (portait and landscape) and the scrollviewer takes care of the rest (using android:adjustViewBounds="true"in the image view to prefent from scrolling over the original size of the image).
I read the guidelines of Google to use different versions for the different resolutions and densities but this seems to be overengineered for my purpose.
My idea was to just supply one high-res (2000px width) image of the images in the drawable folder and let Android auto scaling do the rest.
The only issue I can think of is memory. But I'm not quite sure how the internals work here. If an OutOfMemory only occurs when displaying an image it shouldn't be a problem as the autoscaling hits in first.
If the scaler can run into memory issues I'm thinking using 3 versions of the image with different widths (i.e. 800pixel, 1500pixel and 2200pixel) and put them in different resource directories.
This seems not possible though...
The Android Studio wizard for Resource directories has an option for "smallest screen width" but its only for dp (density-independent pixels)! I want a resource file for real device pixels. I hope Android takes the closest fitting and don't fall back to the default one if it can't find an exact match.
My images don't care about density as they are always filling the screen.
So in a nutshell:
Is supplying just one large pixel image with a small file size an issue?
If yes how can I setup device pixel resource directories?
The nature of the app already has an huge amount of images. That's why I don't want to duplicate each a couple of times which x-folds the number of images to deal with. The app is for API 11 onward.
I finally found a solution to proportionally scale one image to device width with no memory issues.
First you have to draw up your image (my_image.png) in a rather high resolution
Put this image ONLY into the drawable-xxhdpi folder.
Extend the Android ImageView class using this awesome answer.
Use it in your layout as shown below:
Here is layout that works for me:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/main_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
<my.package.name.DynamicImageView
android:id="#+id/main_image"
android:adjustViewBounds="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/main_text_view"
android:src="#drawable/my_image"
android:scaleType="fitXY"/>
<my.package.name.DynamicImageView
android:id="#+id/main_image2"
android:adjustViewBounds="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/main_image"
android:src="#drawable/my_image"
android:scaleType="fitXY"/>
<TextView
android:id="#+id/main_text_view2"
android:layout_below="#id/main_image2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</RelativeLayout>
</ScrollView>
Some more final information:
I did a lot of testing with point 2 (which folder to put the image in) before I found the solution of point 3.
If you put the image in the standard drawable folder the scaling works without point 3 but you might run into OutOfMemory exceptions on older devices as android tries to scale up the already large image (Android thinks in drawable are only small images without checking their size).
When the image is in the drawable-xxhdpi folder Android knows its high-res and does only a down scaling if necessary. But it doesn't scale the image to width on density fitting devices! For example in a Nexus 10 the image gets drawn in its original size and scale - doesn't matter what you set for scaleType (I reckon it has something to do with inTargetDensity as explained in the inScaled description).
One important thing to keep in mind here is that I have to use a ScollView around the whole content. You may find some other solutions when no ScrollView is involved.
Finally, you could also use the drawable-xxxhdpi folder but it was introduced with API 19. I tried it and it worked on lower APIs as well. Apparently Android build tool 19.1.0 and higher takes care of lower API versions.
I hope this helps someone...

Specify drawable size in XML designer

I am making an app in Android Studio and I have just started making the splash screen. However, I have been having trouble making the image show up as the right size/quality in the android:background property.
Here is the XML code that I am using to display the drawable:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="#drawable/main_logo"
android:keepScreenOn="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".Splash">
</RelativeLayout>
The drawable is displayed, but it is a small image in the top left corner of the screen.
The original image is 2500 x 2500 pixels at 9999.99 pixels/inch resolution, so it would have no trouble resizing.
How would I specify to use a different size like xxhdpi instead of hdpi which has been resized, or use the original image and resize it in the center of the screen?
You have to actually provide separate resources for each folder - mdpi, hdpi, xhdpi ... The system chooses the best to use based on the specific device. If only a single resource is provided for all situations, it will be used by default and you, or your client, will likely not like the results.
See Supporting Multiple Screen Sizes for more information.

Set the imagebutoon for different size of device does not working

I add the picture for 48*48 , 72*72 and 96*96 to mdpi , ldpi and hdpi respective.
And add the following code in AndroidManifest.xml
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:anyDensity="true"/>
First Question:
The app will capture the suitable picture by itself when I do the above operation ?
Second Question:
But how to setup the Button in the xml file ?
If app will capture the suitable picture by itself , so I have set the width and the height to match_parent like the following code?
<LinearLayout
android:id="#+id/ImageBtulayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:background="#000000"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageButton
android:id="#+id/BackButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_gravity="center_vertical"
android:background="#drawable/back"/>
<ImageButton
android:id="#+id/recordButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center_vertical"
android:background="#drawable/no_delete" />
<ImageButton
android:id="#+id/download_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_gravity="center_vertical"
android:background="#drawable/download"/>
</RelativeLayout>
</LinearLayout>
I modify the code like the above.
And I install the APP to the device which the size is 4.7 inch.
But the icon seem too small.
It like the following picture
How to remove the part of gray on imageButton ?
Does there has any wrong ??
You are confusing two different concepts. One is a screen's pixel density or DPI and another is a screen's size. In general, phones are considered normal size and tablets are considered large size.
I recommend you read through this entire article which highlights a lot of valuable points regarding supporting different screen sizes and screen densities:
http://developer.android.com/guide/practices/screens_support.html
In general though, Android allows the user to define different resources for different device configurations (including screen size and screen density, among others). This is done through the use of (resource/configuration) qualifiers. These are defined by a hiphen, and then the qualifier name on certain folders inside your /res/ directory.
For example, if you wanted to define different images for different screen densities, you would create a new drawable directory for each supported screen density and put the appropriate resources in each.
/res/drawable-mdpi/
/res/drawable-ldpi/
/res/drawable-hdpi/
Then, when Android goes to look for a resource, it will first look for a directory which matches the device's screen density qualifier and get's the resource from there. The resources will share the same name, but will be in different folders, which allows you to define the different resources but also allows Android to resolve them into their different configurations.
So let's look at your questions:
The app will capture the suitable picture by itself when I do the above operation?
As described above, as long as you have arranged yor resources with the appropriate qualifiers, then yes, Android will be able to resolve them correctly. However, note that this has nothing to do with the tag in your manifest.
But how to setup the Button in the xml file ?
Your current XML setup is correct.
If app will capture the suitable picture by itself , so I have set the width and the height to match_parent like the following code?
Setting your width and height to match_parent will make the views width and height the same as the parent layout, which is incorrect. You want the width and height to wrap the internal content of the view, therefore wrap_content is correct.
Edit: Regarding your question about removing the border, if you want to use ImageButtons, then the documentation (first paragraph) suggests setting the android:background attribute to transparent.
android:background="#00000000"
You might also want to try setting the padding to
android:padding="0dp"
http://developer.android.com/reference/android/widget/ImageButton.html
Answer for the first question:
Android system will choose the image in drawable folder according to device screen density.
Answer for the second question:
If the previous code, you set the height and width of the ImageButton to be wrap_content, so the width and height of the ImageButton will be as the size of the captured image from drawable folder, so if you run on device hdpi then the image size (72*72) and the ImageButton dimensions will be also (72*72) px.
In image button Set Android:src="#drawable/your image"
and set android:background="#null"
it will definatily work for you

Unexpected behaviour while setting a image from res folder to an image view in android

I am using an imageview in my xml and setting an image from res/drawable-xhdpi to it. My image is of 354x404 in size and when i am running the code on a 10" samsung tablet, it showing the image as 177x202.
Here is the code which i am using:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false" >
<ImageView
android:id="#+id/img_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/app_name"
android:src="#drawable/android1" />
</LinearLayout>
Here is the image which i am using:
And this is the screenshot of the tablet:
Please tell why it is happening and what is the solution to resolve this problem.
Update: when i putting this image in "res/drawable" folder instead of xhdpi, it showing the image correctly i.e. 354x404.
Edit after comments:
The ImageView will render the image inside of it at the correct resolution for the device. As per the documentation on providing resources, you must make sure that you provide resources at the correct DPI for each of the resolution types. Android will pick the best resource resolution for you, but if only one resource exists then it will pick that one and try to render at the device resolution.
Samsung tablets, while they have a large screen, are MDPI (the Galaxy Tab 2, at least) which is the standard density even though it has a large screen. Resources for it should be placed in res/drawable.

Still having problems with GridViews

After two years of Android development I'm still not 100% sure about what resources I need to provide to make my GridView work on different size and resolution devices.
I'm still learning, for example I recently discovered that you don't have to supply every drawable in all screen sizes - if you put something in xhdpi then Android is clever enough to resize that on the fly most of the time - but there are a few few quirks. For example if I try using drawables which are only defined in the drawable-xhdpi bin on a mdpi device in a GridView, the drawable will visually resize correctly but the whitespace around it won't - that will still be the original size. Originally I got around this by forcably defining dimensions for all aspects of the GridView and the associated adapter view, but this had a load of code smell around it, so I resized the drawables manually, put them in their respective bins (drawable-mdpi, drawable-hdpi and drawable-xhdpi) and removed all the forcing of image sizes etc.
So I currently have:
<GridView
android:id="#id/home_image_grid"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="100dp"
android:gravity="center"
android:listSelector="#00000000"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
>
</GridView>
and the layout for each item is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dip"
android:gravity="center"
android:orientation="vertical"
android:padding="0dip">
<ImageView
android:id="#id/home_button_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#id/home_button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#color/default_text_colour"
android:textSize="#dimen/home_button_text"
/>
</LinearLayout>
So far so good...
The app I'm currently working on I've almost finished and have been doing some testing on different devices - it looks good on normal screen size xhdpi, hdpi & mdpi devices. Then I extending my testing to other devices - I'm testing on an HTC Flyer which is large screen size, mdpi - and the gridview now looks rubbish - it's correctly picking up the mdpi images, which are tiny.
Doing some reading around I found the GridView tutorial GridView tutorial, which says to put all your drawables in the 'drawable' bin, so I followed this advice and again everything looked rubbish - on closer inspection (and having actually read through the example code) it seems that they are manually setting the size of each image in the GridView - which I'd been doing to start off with, and which means that I'm going to have to manually set the image sizes for every permutation of devices.
So..I'm left wondering if I've missed a trick here - should I take my first approach of sticking the images in my drawable folder and manually forcing the sizes for every purmutation? Should I draw a new set of images for all permutations of screen size and resolution?
How can I guarantee that whatever I do, it's going to look good on a device I've not tested it on?
Either way it feels like I'm doing something wrong - but I can't work out how to do this properly without loads of hassle. Can anyone help?
I'm not sure what you mean by "forcing the sizes for every permutation" but you could put the proper sized drawables in the following folders:
drawable-mdpi
drawable-large-mdpi
Each device would pick the right drawables from the corresponding folder and you could separate normal and large images for mdpi devices.
Wouldn't that fix your problem?
P.S: The drawable folder is meant for XML drawables only or photos which do not depend on the device's density, not images for the UI. Those will scale properly for each resolution and density.

Categories

Resources