3

There are so many material on densities, multiple screen support, so many questions on SO, but I still have not got it.

My goal is simple: display a bitmap as large as available space for ImageView. I need BitMap as I will do some operations on it.

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/figureView" />

I will have some pictures to be used in the bitmap. I will place them in drawables directory. I will reference them with R.drawable.pictureX. I will use Picasso to load them and scale them:

Bitmap bitmap = Picasso.with(getContext()).load(resourceId).resize(w, h).get();

The unclear part for me is all those xxhdpi folders and Android heuristic to select the best.

  1. When a documentation says that Android will automatically scale the image does it apply to my case? I do not want to scale already scaled pictured.

  2. How many dpi variants shall I store in my case and where? Shall I have single file in no-dpi folder or shall I create picture variant for each dpi folder?

  3. How can I determine a dimension for picture resource? It is easy for icons: for example 24x24 dpi and then multiple it with DPI formula. But I want to cover complete screen height. A chapter Configuration examples lists: 240x320 ldpi, 320x480 mdpi, 480x800 hdpi, 720x1280 mdpi, 800x1280 mdpi etc. There are no screen size qualifiers for resources.

Thanks for clarification.

Community
  • 1
  • 1
Leos Literak
  • 8,805
  • 19
  • 81
  • 156

2 Answers2

4

I realized that in fact it is easy to find out Android behavior. I just need each DPI variant different so I can distinguish between them. I put a text with DPI name and pixel resolution inside each picture.

There is a sample GitHub Test DPI project. It has two ImageViews. The first is initialized from XML and Android does scaling. The second is a placeholder that I fill with a BitMap. I entered 200dp as its size and that was correct. Pixel size of MDPI = size in dp.

enter image description here

What I found is logical. Android does not know anything about my intentions. It just selects the best available resource for current DPI.

Nexus 5x uses XXHDPI by default, Samsung SIII Mini uses HDPI. If I delete their default DPI folders, they down-scale higher available variant: XXXHDPI and XHDPI. If I delete all variants except NODPI, this will be used.

And finally if I change the dimensions of ImageView dynamically loaded from source code to 300dp, then it will be scaled and look ugly. Android cannot know at decodeResource execution that I will scale it later and that there is a better resource available.

What remains unknown is how to find out dimensions of picture that fits the screen.

Java:

BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inScaled = false;
Bitmap figureBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_test, opt);
ImageView imageView=(ImageView) findViewById(R.id.testView);
imageView.setImageBitmap(figureBitmap);

Activity:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_test" />
<ImageView
    android:id="@+id/testView"
    android:layout_width="200dp"
    android:layout_height="200dp" />

Update 30th august

Original picture: 230x541 px, loading with

Picasso.with(getContext()).load(R.drawable.amalka).into(target)
  1. stored in nodpi, loaded as 230x541 px Bitmap
  2. stored in xxhdpi, loaded as 230x541 px Bitmap
Leos Literak
  • 8,805
  • 19
  • 81
  • 156
1

1.Android will automatically scale image in case when you provided image for one screen dencity and there is no such image for another one. e.g. if you add your image only in drawable-xxxhdpi folder, Android will generate images for xxhdpi, xhdpi screen dencities etc.

2.You can save your image in one folder drawable-xxxhdpi and let Android make the downscale, if you don't like the result you can create images for different dencities on your own.

name    dencity   scale  
mdpi    160dpi    x1  
hdpi    240dpi    x1.5  
xhdpi   320dpi    x2  
xxhdpi  480dpi    x3  
xxxhdpi 640dpi    x4  

3.You can define dimensions of your images based on size of you ImageView and dpi scale. For example if your ImageView has width 80dp and height 40dp then your image for drawable-mdpi folder should have size 80x40px because mdpi is a baseline dencity, for drawable-hdpi then you need to have image 120x60px (scale is 1.5) etc. For drawable-xxxhdpi your image will be 320x160px.

If you want your image to fit all the screen on all devices you can use parameter android:scaleType="centerCrop", it will make the image take all the space but little part of image can be hidden depending on screen aspect ratio. You can also try to specify image resorces based on shortest dimension of the available screen area, e.g. drawable-sw720dp. Read more about this here.

dzikovskyy
  • 5,027
  • 3
  • 32
  • 43
  • Thank you for your answer. Does Android really always scale the picture? I think that Picasso could use BitmapFactory.Options.inScaled to avoid it. I hope that it can select the best match resource. I will create multiple different variants to check it. – Leos Literak Aug 27 '16 at 04:32
  • If you don't want your image to be scaled you can put it in folder `drawable-nodpi`. But make sure you don't have such image in other drawable forlders, because if you do then image will be taken from other resource. – dzikovskyy Aug 27 '16 at 07:20