Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Putting screen densities into the correct bucket

Tags:

android

A set of six generalized densities:

ldpi (low) ~120dpi mdpi (medium) ~160dpi hdpi (high) ~240dpi xhdpi (extra-high) ~320dpi xxhdpi (extra-extra-high) ~480dpi xxxhdpi (extra-extra-extra-high) ~640dpi 

From the wiki pages of each phone display

Scaling down into the buckets i.e if the ppi is 300 that would go into the hdpi bucket as it less then 320?

Galaxy S3 306ppi -> bucket hdpi Nexus 4  318ppi -> bucket hdpi Nexus 5  445ppi -> bucket xhdpi Nexus 5X 432ppi -> bucket xhdpi Nexus 6  493ppi -> bucket xxhdpi  Nexus 6P 518ppi -> bucket xxhdpi 

Is this the correct way to work out buckets for screen sizes.

The reason I asked is because I have created the following value directory resources:

values-hdpi/dimens values-xhdpi/dimens values-xxhdpi/dimens values-xxxhdpi/dimens 

In the dimens.xml I have different margins and set the dp depending on the bucket size i.e.

<dimen name="network_quantity_margin_top">100dp</dimen> 

I am interested to know if this is the correct way to do this.

like image 384
ant2009 Avatar asked Nov 16 '15 16:11

ant2009


2 Answers

The reason I asked is because I have created the following value directory resources. (...) In the dimens.xml I have different margins and set the dp depending on the bucket size. (...) I am interested to know if this is the correct way to do this.

I'm not sure why you want different margins specified in dp depending on the density. Specifying the margin as dp once, for the baseline density, already handles all other densities for you, meaning that the physical size of the margin will be the same when displayed on any device.

If you used px instead of dp (but don't), then you would have to do the scaling for different screens yourself.

Scaling down into the buckets i.e if the ppi is 300 that would go into the hdpi bucket as it less then 320?

Yes, but not because it is less than 320. If there was a rule of thumb I would say it is rounding to the nearest generalized density. See this illustration of how Android roughly maps actual densities to generalized densities (figure is not exact):

generalized densities

Relevant part of the documentation is this:

Each generalized size and density spans a range of actual screen sizes and densities. For example, two devices that both report a screen size of normal might have actual screen sizes and aspect ratios that are slightly different when measured by hand. Similarly, two devices that report a screen density of hdpi might have real pixel densities that are slightly different. Android makes these differences abstract to applications, so you can provide UI designed for the generalized sizes and densities and let the system handle any final adjustments as necessary.

So again, you shouldn't really care how Android does this if you are just writing an app. What you should care about is:

  • specify all layout dimension values in dp or with wrap_content/match_parent, as appropriate (text can be in sp to additionally match the user preference, but nothing other than text),
  • think about different layouts depending on physical size and orientation of the screen,
  • provide bitmap resources for different densities, just to avoid blurry or pixelated artifacts (because Android will scale them to have the right physical size if you use dp or wrap_content).

Android will lookup the best matching resource, and then transparently handle any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160).

Note the actual density as opposed to generalized density. The latter is only a convenience for the developers, since it would be impossible to provide drawables for every screen out there. This way developers need to provide only 3 or 4 sets of graphics, while Android picks the closest fit and adjusts it further for the needs of that particular device. (Nowadays it's possible to use one vector drawable instead of many pre-scaled raster graphics, meaning better quality and less size.)

Is this the correct way to work out buckets for screen sizes.

No, it is not. According to Google device metrics all devices you listed fall into buckets higher than you expected:

Galaxy S3    NA        NA Nexus 4     318     xhdpi Nexus 5X    424    xxhdpi Nexus 5     445    xxhdpi Nexus 6     493   xxxhdpi Nexus 6P    515   xxxhdpi 

I took some other devices from that list, and plotted how different devices are falling into density buckets depending on their actual physical density.

density buckets of some Android devices

Chromebox 30            101      mdpi Chromebook 11           135      mdpi Samsung Galaxy Tab 10   149      mdpi Nexus 7 '12             216     tvdpi Android One             218      hdpi Chromebook Pixel        239     xhdpi Nexus 9                 288     xhdpi Nexus 10                299     xhdpi Moto X                  312     xhdpi Nexus 4                 318     xhdpi Nexus 7 '13             323     xhdpi  Moto G                  326     xhdpi Dell Venue 8            359     xhdpi LG G2                   424    xxhdpi Nexus 5X                424    xxhdpi HTC One M8              441    xxhdpi Nexus 5                 445    xxhdpi Nexus 6                 493   xxxhdpi Nexus 6P                515   xxxhdpi LG G3                   534    xxhdpi 

You can see, that with some notable exceptions, the rule that the closest generalized density is selected, holds.

The exceptions being Nexus 6 and 6P, that are listed as xxxhdpi, even though LG G3 has a higher physical density and still is far from 640px/in. Android One is hdpi but it is only slightly denser than Nexus 7 '12 which is tvdpi. Chromebox 30 and Chromebook Pixel (admittedly, not Android) are assigned to buckets mdpi and xhdpi even though they are physically lower than ldpi and hdpi, respectively.

like image 190
arekolek Avatar answered Sep 22 '22 08:09

arekolek


I am interested to know if this is the correct way to do this.

You are mostly correct.

The problem lies in this part:


The reason I asked is because I have created the following value directory resources:

values-hdpi/dimens values-xhdpi/dimens values-xxhdpi/dimens values-xxxhdpi/dimens 

In the dimens.xml I have different margins and set the dp depending on the bucket size i.e.

<dimen name="network_quantity_margin_top">100dp</dimen> 

The purpose of dp gets defeated by defining folders like values-hdpi/dimens. Density Pixels, by design, are device-agnostic - 100dp on a device with dpi = 240 will look just as wide/long on a device with dpi = 480. So, if you want your app to look consistent, do not provide different dimensions for different screen densities.

The correct way to think about this is to realize that the only resource that is affected by varying screen densities is drawable. A drawable on a screen with dpi = 240 will look twice as big compared to a screen with density = 480. I am sure that you're providing folders like drawable-hdpi, drawable-xhdpi etc. to deal with this. For everything else, and especially dimensions, use dp. For text sizes, use scaled-pixels - sp.

More importantly, you should worry about the range of different screen sizes that are available for android. How would you use all the extra screen real-estate on a 10 inch device compared to a 5 inch phone? Qualifiers such as -normal, -large, xlarge should be of more interest to you.

To summarize:

  • consider all devices of a certain screen size the same - their screen densities are irrelevant when using density pixels.
  • for every drawable resource you use, place their scaled versions in the buckets you wish to support. Remember that, if you don't provide resources for a certain bucket (say drawable-hdpi), android will scale down your drawables from drawable-xhdpi folder (provided drawable-xhdpi is defined). The reverse is also true: if you have placed all your drawables in drawable-xhdpi, android would scale-up your drawables on a xxhdpi device. The result will be blurry graphics - because of scaling-up.

I know that its a bit of a steep slope here :). So, if you need to clarify some more, leave me a comment.

like image 21
Vikram Avatar answered Sep 21 '22 08:09

Vikram