127

Is there any way to set the height/width of a LayoutParams as density-independent pixels (dp)? It looks like the height/width, when set programmatically, are in pixels and not dp.

Cœur
  • 37,241
  • 25
  • 195
  • 267
psychotik
  • 38,153
  • 34
  • 100
  • 135

5 Answers5

275

You need to convert your dip value into pixels:

int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, <HEIGHT>, getResources().getDisplayMetrics());

For me this does the trick.

Serhat Ozgel
  • 23,496
  • 29
  • 102
  • 138
Mokus
  • 3,339
  • 1
  • 24
  • 30
  • 10
    I think that getActivity().getResources().getDimension(resourceID) do the correct converting operations. – StErMi Mar 30 '12 at 10:26
  • 3
    Works for me, but it differs... if I set the width/height of an ImageView using the method above vs. using the xml. In the XML I set 85dp while the method above needs "75" to produce the same size. Any idea why? – Dirk Sep 18 '14 at 23:26
  • 1
    @Dirk There is probably a padding/margin issue when you set it programatically (usually you have to specify the padding yourself when you set in code). There should be not difference whatsoever between setting dp in XML or in code. – Bitcoin Cash - ADA enthusiast Oct 23 '14 at 08:59
11
 public static int getDPI(int size, DisplayMetrics metrics){
     return (size * metrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;        
 }

Call the function like this,

DisplayMetrics metrics;
metrics = new DisplayMetrics();         
getWindowManager().getDefaultDisplay().getMetrics(metrics);

int heigh = getDPI(height or width, metrics);
Xavi
  • 20,111
  • 14
  • 72
  • 63
Hades
  • 3,916
  • 3
  • 34
  • 74
  • That is... really wrong. You have hard-coded to only support a fixed number of densities. If you want to scale by the density scaling factor, just multiply by http://developer.android.com/reference/android/util/DisplayMetrics.html#density which would also be the same as doing (size * metrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT. – hackbod May 11 '11 at 06:47
  • 1
    Yes your new answer is reasonable. Or as I said, just multiply by metrics.density. That is what it is for. – hackbod May 11 '11 at 22:07
7

Since it may be used multiple times:

public static int convDpToPx(Context context, float dp) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
}

I found it more practical to use the conversion rate, as usally more than one value has to be converted. Since the conversion rate does not change, it saves a bit of processing time.

/**
 * Get conversion rate from dp into px.<br>
 * E.g. to convert 100dp: px = (int) (100 * convRate);
 * @param context e.g. activity
 * @return conversion rate
 */
public static float convRateDpToPx(Context context) {
    return context.getResources().getDisplayMetrics().densityDpi / 160f;
}
Gunnar Bernstein
  • 6,074
  • 2
  • 45
  • 67
5

Here is my snippet:

public class DpiUtils {

    public static int toPixels(int dp, DisplayMetrics metrics) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
    }

}

where DisplayMetrics metrics = getResources().getDisplayMetrics()

Roman
  • 860
  • 14
  • 14
0

The answered solution didn't work for me, the height of the view was still off. I ended up with this, which works well:

protected int dp2px(int dp){
    final float scale = getResources().getDisplayMetrics().density;
    return (int) (dp * scale + 0.5f);
}

And if you want the other way round, pixels to dp ...

protected float px2dp(float px){
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float dp = px / (metrics.densityDpi / 160f);
    return Math.round(dp);
}
Mr L
  • 470
  • 6
  • 16