93

I have known the difference among DP, SP and PX. And after searching this topic, I found nothing satisfying me completely. Maybe this post is a duplicate, but I still want to know what is the formula of converting from DP to PX, and DP to SP, from SP to PX, from PX to SP, from SP to DP, from DP to SP? I have known some codes to do this, but they are imperfect.

SilentKnight
  • 13,435
  • 18
  • 48
  • 78

6 Answers6

218

DP to PX:

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

SP to PX:

public static int spToPx(float sp, Context context) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}

DP to SP:

public static int dpToSp(float dp, Context context) {
    return (int) (dpToPx(dp, context) / context.getResources().getDisplayMetrics().scaledDensity);
}
AndroidEx
  • 14,884
  • 9
  • 53
  • 50
  • @Android777 Your former two code segment seem fresh. @DerGolem But why `dp = sp`, `device-independent pixel` is equal to `scaled-pixel`? – SilentKnight Apr 16 '15 at 10:01
  • @SilentKnight Derived from this post (specifically from the image): http://stackoverflow.com/a/2025541/2649012 – Phantômaxx Apr 16 '15 at 10:07
  • When a `TextView` is called `setScaleX` or `setScaleY`, both are equal too? – SilentKnight Apr 16 '15 at 10:12
  • When `android:scaleX = "integer"` or `android:scaleY = "integer"` are set of a `TextView`, both are equal too? – SilentKnight Apr 16 '15 at 10:33
  • @DerGolem according to my knowledge, **sp** and **dp** can be different because sp takes into account user font size preferences as well. I believe that picture describes only one possible situation. – AndroidEx Apr 16 '15 at 14:04
  • 1
    @DerGolem I wish I could find a solid example illustrating when they can be same and different, but I feel it's kind of a grey area. Many people (including me) know what dp and sp, and hypothetical differences between them, but some practical aspects are still in the dark. – AndroidEx Apr 16 '15 at 14:19
  • @SilentKnight I noticed you amended your question. Do you want me to add other conversion directions you specified? Because I think it'll be some variation (inversion) of the existing ones, not too interesting. – AndroidEx Apr 16 '15 at 14:20
  • 1
    @Android777. Well, they are `mostly` the same. As a rule of the thumb, always use `dp` for Views and `sp` for fonts. And you'll never fail. Sincerely, I've never investigated any further, since I follow this `golden rule`. – Phantômaxx Apr 16 '15 at 14:33
  • 1
    @DerGolem I totally agree, but then we come across a question about conversion between dp and sp, and we are not sure if this is a valid thing to consider... – AndroidEx Apr 16 '15 at 14:54
  • Anyway... I rarely even consider converting px to dp and vice versa. Because I'm sure that Android does its best to scale my dps and sps correctly. Although there are occasions where I need to scale something which is given in pixels or pass a parameter to some method which expects pixels. – Phantômaxx Apr 16 '15 at 15:30
  • 1
    @AndroidEx You are correct. SP can be different than DP based on user preferences for text size. Conversion from sp to px or dp would be necessary for example in custom drawing where you want a graphic's size to correspond in some way to text drawn on a canvas. – Mitselplik May 29 '16 at 19:13
  • `"DP to SP: (why would you need it?)"`, e.g. I set size for figures and texts programmatically (depending on width of phone), and text should take 50% of figure. I get size-value of figure in dp and somehow have to calculate sp so text will take 50% of figure. So nothing strange.. – user25 Sep 11 '16 at 15:00
  • p.s. here is google official info about `Converting dp units to pixel units`: https://developer.android.com/guide/practices/screens_support.html I don't if it works the same like in your answer (I use google's info, works right) – user25 Sep 11 '16 at 15:13
  • @user25 If you are talking about this line `final float scale = getResources().getDisplayMetrics().density;` in the docs than `applyDimension()` does pretty much [the same](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/util/TypedValue.java#TypedValue.applyDimension%28int%2Cfloat%2Candroid.util.DisplayMetrics%29) – AndroidEx Sep 11 '16 at 18:33
  • @anonymos I have a custom Toast layout that appears at the bottom center of the screen with variable text. I subtract 1/2 of the text width from it to maintain center because I know the required DP value, but need to account for text size. – Abandoned Cart Apr 19 '17 at 16:20
  • 2
    sp one is wrong the correct one public static int convertDpToSp(float dp, Context context) { return (int) (convertDpToPixels(dp, context) / context.getResources().getDisplayMetrics().scaledDensity); } – user49557 Oct 05 '17 at 10:38
  • 1
    The difference between DP and SP is that SP is scaled based on the user's font size preference. You can't treat the two as being the same, it's totally wrong. That's why all text should be specified in SP and (almost) everything else in DP. – HughHughTeotl Sep 11 '18 at 08:41
  • Not work for me: https://stackoverflow.com/questions/55972518/not-correct-return-text-size-in-sp – Alex May 04 '19 at 11:29
  • 1
    I was testing it and I have to use COMPLEX_UNIT_PX to get the real size in PX for SP. I don't know why but if use the COMPLEX_UNIT_SP I got a huge and not real text size. Should be great if @AndroidEx can confirm us if this is correct or it is a bug in COMPLEX_UNIT_SP. – JavierSegoviaCordoba Jun 16 '19 at 17:23
92

The accepted answer is missing a few useful conversions.

SP to PX

float sp = 20;
float px = sp * getResources().getDisplayMetrics().scaledDensity;

or

float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());

PX to SP

float px = 70;
float sp = px / getResources().getDisplayMetrics().scaledDensity;

DP to PX

float dp = 20;
float px = dp * getResources().getDisplayMetrics().density;

or

float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());

PX to DP

float px = 70;
float dp = px / getResources().getDisplayMetrics().density;

Notes

  • The floats I chose above (20 and 70) were arbitrary values. You can plug in different numbers if you like.
  • px refers to pixels. The number of pixels that a device has per inch of screen space is called the density.
  • dp means density-independent pixels. That is, no matter what device is used, the actual size should be the same. For example, if I set a view to be 100 dp wide, it will have the same width on a new high density phone as it does on an old low density phone. (If I had set the width to 100 px, on the other hand, it would appear large on a low density phone and small on a high density phone.) Density is measured in dots per inch (DPI). The formula is px = dp * density. So you just multiply or divide by the density to convert between px and dp.
  • sp means scale-independant pixels. It is just used for fonts, not views. It is similar to dp except it also factors in the user preferences. This density with user preferences taken into account is known as scaled density. Setting a TextView font to a size of 30 sp, for example, will make the text generally appear to be the same physical size on all devices. However, your grandmother may have her preferred font size maxed all the way up in her phone settings, so 30 sp text will look bigger on her phone than it does on yours. The formula is px = sp * scaledDensity.
  • Meaning of DP and SP
  • DP to SP conversion is not generally useful
Suragch
  • 428,106
  • 278
  • 1,284
  • 1,317
9

For converting Dimension to Integer or Pixel you need to use "getDimensionPixelSize(R.dimen.your_dp_value)" function, Like...

Make a value in dimens.xml

<dimen name="padding_10">10dp</dimen>

Now for That value in pixel or integer you can use as like below:

int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.padding_10);
varotariya vajsi
  • 3,857
  • 38
  • 38
  • Cleanest solution IMHO, without mentioning that splitting the file in values-* you can get different values for different densities, if needed... – Shockwaver Aug 01 '18 at 09:34
6

For kotlin I created an extension function:

fun Number.spToPx(context: Context) = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_SP, this.toFloat(), context.resources.displayMetrics).toInt()

You can use it like 16.spToPx(context) or 16.5.spToPx(context)

(I place such functions in a KotlinExtensions.kt file)

Vedant Agarwala
  • 17,082
  • 4
  • 65
  • 81
2

You can write a method, that doesn't need context or resources:

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

public static int spToPx(int sp) {
    return (int) (sp * Resources.getSystem().getDisplayMetrics().scaledDensity);
}

By analogy, other quantities can be converted.

Nicholas Oli
  • 101
  • 1
  • 2
  • `Resources.getSystem()` is not configured for the current screen and cannot use dimension units according to the documentation – T - Gott Oct 17 '20 at 12:24
0

According to TypedValue#applyDimension source code and take advantage of Kotlin extension:

val Float.toSp get() = this * Resources.getSystem().displayMetrics.scaledDensity

Other extensions from link

val Float.toPx get() = this * Resources.getSystem().displayMetrics.density

val Float.toDp get() = this / Resources.getSystem().displayMetrics.density
beigirad
  • 3,923
  • 1
  • 21
  • 45