Why displayMetrics.density is wrong?

698 Views Asked by At

On my Pixel 7 device, I want to know how many density-independent pixels (dp) I have. So, I use this formula:

displayMetrics.widthPixels / displayMetrics.density

However, I have an issue because displayMetrics.widthPixels = 1080 (which is okay) and displayMetrics.density = 2.625. When I calculate 1080 / 2.625, it equals 411.428571 density-independent pixels, which is not an integer. It seems that displayMetrics.density = 2.625 may be incorrect because it's unusual to have a fraction of a density-independent pixel.

How can I obtain the correct value for displayMetrics.density? I suppose it's 2.62135922, which would result in 412 density-independent pixels, making it seem more visually appealing.

2

There are 2 best solutions below

1
Krokomot On BEST ANSWER

Looking at the Android's official dp-px conversion formula, one can say your calculation as such is correct. And displayMetrics.density is not wrong. The thing is, that

One dp is a virtual pixel unit that's roughly equal to one pixel on a medium-density screen (160 dpi, or the "baseline" density). Android translates this value to the appropriate number of real pixels for each other density.

This definiton of one dp is platform-dependent, e.g. Windows has another one. So your formula is indeed

    px = dp * (dpi / 160)
<=> px = dp * displayMetrics.density
<=> dp = px / displayMetrics.density
<=> dp = displayMetrics.widthPixels / displayMetrics.density

as density is defined as dpi/160.

However, as the holy docs say

Never hardcode this equation

and one should use applyDimension() for the conversion from dp to px. Analogously, deriveDimension() converts px to dp.

Now you say: "Wait a moment, deriveDimension() only comes with Android 14. What shall I do in the meantime?"

Note, that applyDimension() and deriveDimension() both return float values. The docs' example for applyDimension() applies a type conversion to Integer on the result.

So -- keep using your formula for now and simply add a type conversion of the result to Integer.

6
Marcin Orlowski On

But density actually is a type of float:

public float density

[...] This value does not exactly follow the real screen size (as given by xdpi and ydpi), but rather is used to scale the size of the overall UI in steps based on gross changes in the display dpi.

https://developer.android.com/reference/android/util/DisplayMetrics#density