What is the correct way to specify dimensions in DIP from Java code?

I found that it is possible to set dimensions of my interface elements in XML layouts using DIPs as in following fragment:

android:layout_width="10dip"

But all Java interface takes integer as arguments and there is no way to specify dimensions in DIPs. What is the correct way to calculate this?

I figured that I have to use property density of DisplayMetrics class but is this a correct way?

May I rely on this formula being always correct?

pixels * DisplayMetrics.density = dip

Is there a utility function for the conversion somewhere in Android?


Solution 1:

There is an existing utility method built called TypedValue.applyDimensions(int, float, DisplayMetrics) that does this.

Here's how to use it:

// returns the number of pixels for 123.4dip
int value = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
                     (float) 123.4, getResources().getDisplayMetrics());

There's a list of other types that you can use with it including COMPLEX_UNIT_SP, COMPLEX_UNIT_PT all found in the page I linked above. If you exclude the (int) typecast, you'll get the floating point number.

I encountered the same problem and found this through poking around the code.

Solution 2:

That is the correct formula there. Although DisplayMetrics.density is not a static member, so, according to the same document you alluded to, correct usage is:

// Maybe store this in a static field?
final float SCALE = getContext().getResources().getDisplayMetrics().density;

// Convert dips to pixels
float valueDips = 16.0f;
int valuePixels = (int)(valueDips * SCALE + 0.5f); // 0.5f for rounding

Solution 3:

Using the display metrics density field, you can get a scaling factor to convert to/from dips. Use the Math.round method to convert from a float to an int without needing a cast or adding 0.5

// Converting dips to pixels
float dips = 20.0f;
float scale = getContext().getResources().getDisplayMetrics().density;
int pixels = Math.round(dips * scale);

// Converting pixels to dips
int pixels = 15;
float scale = getContext().getResources().getDisplayMetrics().density;
float dips = pixels / scale;

Solution 4:

I think the best way is not to define any dimensions in code, but use the values/dimens.xml file instead. You can always define your dimension in the desired unit like:

<dimen name="my_layout_height">120dp</dimen>

and then refer to this in your Activity like:

getResources().getDimensions(R.dimen.my_layout_height);

This would return pixels after doing the necessary conversions. And also of course you can refer to this in your other XMLs like:

android:layout_width="@dimen/my_layout_height"