Scalable pixels (sp) serve the same function as density-independent pixels (dp), but for fonts. The default value of an sp is the same as the default value for a dp. The primary difference between an sp and a dp is that sp's preserve a user's font settings.
Definitions. px or dot is a pixel on the physical screen. dpi are pixels per inch on the physical screen and represent the density of the display. dip or dp are density-indenpendant pixels, i.e. they correspond to more or less pixels depending on the physical density.
px: our usual standard pixel which maps to the screen pixel. in: inches, with respect to the physical screen size. mm: millimeters, with respect to the physical screen size. pt: 1/72 of an inch, with respect to the physical screen size.
The Android documentation used to incorrectly state that 160 dp always equals 1 inch regardless of screen density. This was reported as a bug which was accepted and the documentation updated.
From the updated documentation:
160 dp will NOT always equal 1 inch, it will vary with different screen sizes and densities. On a screen with a density of 160dpi (mdpi), 160 dp will equal 1 inches.
1 pt will always equal 1/72 in, regardless of the screen density.
The Android documentation for this is here.
UPDATE:
I made a small application to try and verify the different sizes. It looks like what is above is correct, at least when shown on my HTC Aria. Here is a screenshot:
It's interesting to note that these sizes did NOT match up exactly in the eclipse graphical editor. The dp and sp sizes wavered depending on the size of the screen and resolution in the editor. Here are some screenshots from the editor (left is 2.7in QVGA slider, right is 10.1in WXGA, clipped):
It would be interesting to see if these editor renders match up with the actual devices. Can anyone verify these sizes? I'll attach my xml below in case anyone wants to help out.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="22sp" android:padding="5sp" android:text="160dp"></TextView>
<View android:id="@+id/view1" android:layout_height="20dip" android:layout_width="160dp" android:layout_marginLeft="20sp" android:background="#FF22FF22"></View>
<TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="22sp" android:padding="5sp" android:text="72pt"></TextView>
<View android:id="@+id/view2" android:layout_height="20dip" android:layout_width="72pt" android:layout_marginLeft="20sp" android:background="#FF22FF22"></View>
<TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="22sp" android:padding="5sp" android:text="1in"></TextView>
<View android:id="@+id/View01" android:layout_height="20dip" android:layout_width="1in" android:layout_marginLeft="20sp" android:background="#FF22FF22"></View>
<TextView android:layout_width="wrap_content" android:textSize="22sp" android:layout_height="wrap_content" android:text="160sp" android:padding="5sp" android:id="@+id/TextView01"></TextView>
<View android:layout_marginLeft="20sp" android:layout_width="160sp" android:id="@+id/View04" android:background="#FF22FF22" android:layout_height="20dip"></View>
<TextView android:layout_width="wrap_content" android:textSize="22sp" android:layout_height="wrap_content" android:padding="5sp" android:id="@+id/TextView02" android:text="160px"></TextView>
<View android:layout_marginLeft="20sp" android:id="@+id/View03" android:background="#FF22FF22" android:layout_height="20dip" android:layout_width="160px"></View>
<TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="22sp" android:padding="5sp" android:text="25.4mm"></TextView>
<View android:id="@+id/View02" android:layout_height="20dip" android:layout_marginLeft="20sp" android:background="#FF22FF22" android:layout_width="25.4mm"></View>
</LinearLayout>
Edit: Added 2 more devices to John's example. On the left a Samsung Nexus S (OS 2.3.3). On the right, a Samsung Galaxy Tab 10.1 (OS 3.1). No mods.
On the Nexus S, 160dp is slightly larger than 1 inch. All the normal physical units (in, mm, pt) are all the same size. I measured it with a ruler, and the 160 dp bar is about 1mm larger than it should. While the physical units are 1mm shorter than they should.
On the Tab, all bars are exactly the same, and 1mm longer than what I measured with a ruler.
The documentation says that 160 dp (density-independent) equals 1 inch. And 72 pt is also 1 inch.
The nuance here is that 160 dp
(or dip
) is roughly 1 inch, while 72 pt
is exactly 1 inch. The difference is how android converts both units to pixels, which depends on the screen density of the device.
A single dp
is a single px
on a device at 160 dpi. Android uses the "density bucket" the device falls into, and multiplies a scaler to convert dp
to px
.
Bucket | DPI | Scaler
---------------------
ldpi | 120 | 0.75
mdpi | 160 | 1.00
tvdpi | 213 | 1.33
hdpi | 240 | 1.50
xhdpi | 320 | 2.00
xxhdpi | 480 | 3.00
dp
to px
converts following this formula: dp * scaler = px
.
A single pt
is exactly 1/72 of an inch on any screen density. Android converts pt
to px
using the exact dpi (xdpi and ydpi) of the device's screen.
pt
to px
converts following this formula: pt / 72 * dpi = px
.
So I don't see why android define a dp measurement while it seems to work the same as points. Can anybody explain that? Why should I use dp if I can use pt?
Take an example, display 160 dp
and 72 pt
on a 160 dpi device. A 160 dpi device falls into the mdpi density bucket, with a scaler of 1.0. Use the formulas above to convert to px
.
160 dp * 1.0 = 160 px
72 pt / 72 * 160 = 160 px
What about on a 170 dpi device? A 170 dpi device falls into the mdpi density bucket, with a scaler of 1.0.
160 dp * 1.0 = 160 px
72 pt / 72 * 170 = 170 px
What about on a 150 dpi device? A 150 dpi device falls into the mdpi density bucket, with a scaler of 1.0.
160 dp * 1.0 = 160 px
72 pt / 72 * 150 = 150 px
The moral of the story is, dp
keeps exact dimensions and helps keep performance, allowing some physical size variation depending on device density. On the other hand, pt
is exactly the same physical size on every density, which leads to a different amount of px
being used, which can hinder performance and cause aliasing and artifacts if used on images. dp
is recommended unless absolutely exact physical dimensions are required (you have a ruler on screen, etc).
I have written an in depth blog on Android's dimension units, which gives more info and sample code - Understanding Density Independence in Android
Out of curiosity, I tried the layout from John's answer on my two devices: Asus Transformer (10.1 in) and HTC Legend (3.2 in). The results were pretty interesting:
Transformer (cropped):
And Legend:
I've struggled with dimensions but I think I've found a way of looking at it that makes sense to me. There's a conversion formula in Wei-Meng Lee's "Beginning Android 4 Application Development" (pg 111):
Actual pixels = dp * ( dpi / 160 ), where dpi is either 120, 160, 240 or 320
So, using that formula, I can find which dpi for my phone/emulator is closest to one of those four values and that'll determine the ratio (3/4, 1, 3/2 or 2) used in the formula to convert dp to pixels. It's important to me that dpi in the formula can only assume one of those four values despite the actual device pixel density.
Referring to: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density, for a Nexus S with a pixel density of 235 dpi the conversion is:
pixels = dp * 3/2
So a 160dp button, say, would be 240px (a little wider than an inch with the device's 235 dpi)
For an HTC Legend, with a pixel density of 181 dpi the formula is:
pixels = dp * 1
(because 181 is closest to 160). So that 160dp button would be 160pixels, or slightly less than an inch on the device with its pixel density of 181dpi.
This helps me understand the incorrectness of the previous Android documentation "1 dp will always equal 1/160in, regardless of screen density".
These are the two main points I'm trying to get in my head :)
pt Points - 1/72 of an inch based on the physical size of the screen.
dp Density-independent Pixels - an abstract unit that is based on the physical density of the screen. These units are relative to a 160 dpi screen, so one dp is one pixel on a 160 dpi screen. The ratio of dp-to-pixel will change with the screen density, but not necessarily in direct proportion. Note: The compiler accepts both "dip" and "dp", though "dp" is more consistent with "sp".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With