52

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?

Octavian Helm
  • 39,405
  • 19
  • 98
  • 102
Pavel Lahoda
  • 219
  • 1
  • 4
  • 7

4 Answers4

92

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.

sirhc
  • 6,097
  • 2
  • 26
  • 29
  • 12
    This converts pixels into DIP rather than DIP into pixels which I believe is what the OP wanted. Certainly it was what I wanted. Which you do like so: `(int)(desiredDIP * context.getResources().getDisplayMetrics().density)` – mxcl Feb 22 '12 at 23:32
46

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
Roman Nurik
  • 29,665
  • 7
  • 84
  • 82
  • 1
    Thanks Roman, I somehow overlooked this part. There are two extra topic-related questions : - will the density be always equal for both dimensions ? It seems so (as this is just one value), but perhaps there is some other formula for calculating this. - isn't there any API to do the conversion for me ? Do I really have to write the following snipped in my code ? In XML layout code, it is possible to specify "dip" as unit, why it's not possible in Java API ? – Pavel Lahoda Feb 10 '10 at 19:25
  • 1
    I think you can safely assume density being equal in both dimensions. Remember, DisplayMetrics.density is the **logical density**, not the actual screen density (which may slightly vary from the logical density). Regarding a conversion API, it's trivial to write a helper method like say, `Util.dip` that converts dip's to pixels for use in function calls. It's cleaner to handle units in Java that way anyway. – Roman Nurik Feb 10 '10 at 20:00
9

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;
Matt Stoker
  • 350
  • 4
  • 7
5

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"
ercan
  • 1,639
  • 1
  • 20
  • 34