Formula px to dp, dp to px android

174,500

Solution 1

Note: The widely used solution above is based on displayMetrics.density. However, the docs explain that this value is a rounded value, used with the screen 'buckets'. Eg. on my Nexus 10 it returns 2, where the real value would be 298dpi (real) / 160dpi (default) = 1.8625.

Depending on your requirements, you might need the exact transformation, which can be achieved like this:

[Edit] This is not meant to be mixed with Android's internal dp unit, as this is of course still based on the screen buckets. Use this where you want a unit that should render the same real size on different devices.

Convert dp to pixel:

public int dpToPx(int dp) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));     
}

Convert pixel to dp:

public int pxToDp(int px) {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

Note that there are xdpi and ydpi properties, you might want to distinguish, but I can't imagine a sane display where these values differ greatly.

Solution 2

I solved my problem by using the following formulas. May other people benefit from it.

dp to px:

displayMetrics = context.getResources().getDisplayMetrics();
return (int)((dp * displayMetrics.density) + 0.5);

px to dp:

displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((px/displayMetrics.density)+0.5);

Solution 3

Efficient way ever

DP to Pixel:

private int dpToPx(int dp)
{
    return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

Pixel to DP:

private int pxToDp(int px)
{
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

Hope this will help you.

Solution 4

px to dp:

int valueInpx = ...;
int valueInDp= (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, valueInpx , getResources()
                .getDisplayMetrics());

Solution 5

Just call getResources().getDimensionPixelSize(R.dimen.your_dimension) to convert from dp units to pixels

Share:
174,500

Related videos on Youtube

Bram
Author by

Bram

Updated on November 12, 2021

Comments

  • Bram
    Bram over 2 years

    I am trying to calculate a variable amount of pixels to density independent pixels and vice-versa.

    This formula (px to dp): dp = (int)(px / (displayMetrics.densityDpi / 160)); does not work on small devices because it is divided by zero.

    This is my dp to px formula:

    px = (int)(dp * (displayMetrics.densityDpi / 160));
    

    Could someone give me some pointers?

    • Padma Kumar
      Padma Kumar over 12 years
      Converting dp units to pixel units developer.android.com/guide/practices/…
    • ct_rob
      ct_rob over 12 years
      @Bram: I think your formula is just fine. How will you get a division by zero? displayMetrics.densityDpi will be either 120, 160, 240 or 320, never 0.
    • TomTaila
      TomTaila over 7 years
      I agree with @ct_rob . displayMetrics.densityDpi / 160 minimum value will be 0.75. You must have been casting to int in the incorrect place.
  • ct_rob
    ct_rob over 12 years
    although, now that i think about it...how will there ever be a divsion by zero in Brams original formula? displayMetrics.densityDpi will be either 120, 160, 240 or 320, never 0.
  • Admin
    Admin over 12 years
    (displayMetrics.densityDpi / 160) - this part can get 0 on small devices, there it calculates for example 120/160, both values are int, which results in 0. Which ends up as (int) (px/0).
  • ct_rob
    ct_rob over 12 years
    ah, you're right. So all he needs to do is use a long in his formula: 160.0
  • Kelly Copley
    Kelly Copley almost 12 years
    @Vame The adding of 0.5 is used to round UP to the nearest integer value.. The 0.5 is added and then the result of the calculation is cast as an int causing it to truncate the mantissa and leaving characteristic as a properly rounded integer value.
  • PaNaVTEC
    PaNaVTEC about 11 years
    This is from DP to PX, but with this correction: typedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, valueInDp , getResources() .getDisplayMetrics()); is from PX to DP, also this is the best answer
  • Marek
    Marek about 11 years
    This is not always correct. When I have two layouts one inside another and then I round corners of each view (one by using dp, other converting to dp) corners doesn't match!
  • Bram
    Bram about 11 years
    I didn't have any problems with this technique. I used this for different layouts and it always worked as expected. Of course I used this few years ago and I am not sure if it still works. Perhaps you could try the other technique in PanaVTEC's answer. It could also be that there is more to rounding corners than just dp / px calculations.
  • Bachi
    Bachi almost 11 years
    the density value is not exact, but rather adjusted in steps. From the docs: 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. For example, a 240x320 screen will have a density of 1 even if its width is 1.8", 1.3", etc.. If you need an exact conversion, better use displayMetrics.xdpi and displayMetrics.ydpi (see my example below)
  • alocaly
    alocaly about 10 years
    It's the same solution that is adopted on the Android developer site, so I guess it's correct :) . http://developer.android.com/guide/practices/screens_support‌​.html#dips-pels
  • nibarius
    nibarius about 10 years
    This will not calculate the correct value for dp/px on many devices (including your Nexus 10)! As you say displayMetrics.density is rounded to the nearest screen bucket, but so is the dp unit! Try drawing one object that is 160dp wide and just below it you draw another object that is dpToPx(160) pixels wide and you will see that the size of the two objects are different. Also some phones (such as Galaxy Mini and Galaxy S3 Mini) report completely wrong values for xdpi/ydpi so on these phones your methods will return completely wrong results.
  • Bachi
    Bachi about 10 years
    @nibarius Yes you cannot mix Android's boxed dp calculations with the above. The above solution is meant as a separate density independent value based on the exact device physics. Needed eg where you want to show a line the exact same real length on different devices. Of course if the xdpi/ydpi inputs are not correctly set by some devices, it wont't work there.
  • nibarius
    nibarius about 10 years
    Thanks for the clarification, when you need a fixed physical size this is the way to go.
  • Mark McClelland
    Mark McClelland about 10 years
    xdpi and ydpi should not be used, because they are inaccurate on many devices, sometimes by a lot. Only DisplayMetrics.densityDpi is reliable, which is unfortunate, since it is imprecise by design. See Google forum thread for more info: groups.google.com/forum/#!topic/android-developers/g56jV0Hor‌​a0
  • Bahadır Yıldırım
    Bahadır Yıldırım about 10 years
    I prefer this one as it includes xxhdpi and xxxhdpi and other units of measure.
  • william gouvea
    william gouvea almost 10 years
    I found this response and actually used many similar solutions but I just went through the docs and found getDimensionPixelOffSet with given a dimension(declared in dip/dp) returns the offset in pixels just like the handmade code. I tested and worked flawlessly. Hope it helps!
  • Simon Dorociak
    Simon Dorociak over 9 years
    +1 Thanks man. Worked like a charm! Thank you for sharing this solution with us.
  • Stephen Niedzielski
    Stephen Niedzielski about 9 years
    @PaNaVTEC, the solution you referenced for dp to px is incorrect. applyDimension only yields pixels. See android.googlesource.com/platform/frameworks/base/+/refs/hea‌​ds/… wherein no conversion is performed for COMPLEX_UNIT_PX.
  • CJBS
    CJBS almost 9 years
    Per the documentation, this is the same as getDimension(), except the returned value is converted to integer pixels for use as a size. A size conversion involves rounding the base value, and ensuring that a non-zero base value is at least one pixel in size.
  • いちにち
    いちにち about 8 years
    Just to clarify that this method will not always give the correct value. Use the accepted answer instead.
  • Bram
    Bram almost 8 years
    nice addition to the given solutions.
  • Lorne Laliberte
    Lorne Laliberte almost 8 years
    I would be surprised if the conversion calculation wasn't at least as fast as a map lookup, not to mention a synchronized one. Do you have any test results to demonstrate this optimization is beneficial? On Android where working memory is limited, trading memory for calculation effort isn't something you should do without good reason.
  • bitbybit
    bitbybit almost 8 years
    This answer is plain wrong. It returns final values in pixels, never in dp. If you look at the source code, for the case TypedValue.COMPLEX_UNIT_DIP, value * metrics.density is returned, where you actually need value * metrics.density. So what you are getting` valueInDp` is NOT in dp for valueInPx in px.
  • bitbybit
    bitbybit almost 8 years
    ^typo, I meant "...where you actually need value / metrics.density"
  • Ayaz Alifov
    Ayaz Alifov over 7 years
    Better because there is no need to use Context :) Thanks.
  • Rik van Velzen
    Rik van Velzen almost 7 years
    Mehhh, this doesn't give correct value. Try: Resources r = getResources(); float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, r.getDisplayMetrics()); As described here: stackoverflow.com/questions/4605527/converting-pixels-to-dp
  • John smith
    John smith over 6 years
    this answer is similar to upper one because of DisplayMetrics.DENSITY_DEFAULT has 160 value. but can you please let us know what is DPI here how we calculate it.
  • Bram
    Bram over 6 years
    @CelalOzanBerkYavuz could you elaborate what does not work?
  • toom
    toom almost 6 years
    Best answer! Unfortunately the "Marked as correct" answer is wrong. Especially since it uses displayMetrics.xdpi which is different on any device. Sadly, this wrong answer additionally has the most upvotes.
  • user924
    user924 over 5 years
    why are you hardcoding displayMetrics.xdpi ? this answer doesn't use xdpi: stackoverflow.com/a/8490361/7767664
  • user924
    user924 over 5 years
    this should be easier (int) ((dp * App.getContext().getResources().getDisplayMetrics().density) + 0.5)
  • Raphael C
    Raphael C over 4 years
    nice. should be marked as best answer. kotlin: private fun dpToPx(dp: Int) = (dp * Resources.getSystem().displayMetrics.density).toInt()
  • EpicPandaForce
    EpicPandaForce about 2 years
    Not better, Resources.getSystem() is not always correct
  • EpicPandaForce
    EpicPandaForce about 2 years
    Apparently return dp * context.getResources().getDisplayMetrics().density; works
  • Pang
    Pang about 2 years
    Link in answer is dead - "The domain Skinkers.com may be for sale. Click here to inquire about this domain."
  • Malwinder Singh
    Malwinder Singh about 2 years
    Why negative vote?