Android中 dip 和 px 的关系

当我们要在Layout 中定义控件的长宽等维度时,Android的推荐是:

1)所有长宽的单位都定义成dip,除了字体的大小

2)字体的大小用sp来表示

这篇文章我们讨论一下,为什么不用像素 px, 而要用dip 表示呢? dip 跟 px 之前的关系是什么呢?

实践出真知,代码来展示。

我们先来定义两个按钮,其中一个的宽度是160 dip, 另外一个的宽度是160 px,(注意单位不同)然后来看看在不同的模拟器上有什么不一样。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
     <TextView android:id="@+id/textViewSw"
        android:layout_width="320dip"
        android:layout_height="wrap_content"
        android:background="#00CC77"
     />
    
    <Button 
        android:layout_width="160dip"
        android:layout_height="wrap_content"
        android:text="160dip">       
    </Button>
    
    <Button 
        android:layout_width="160px"
        android:layout_height="wrap_content"
        android:text="160px">       
    </Button>
    
    <TextView android:id="@+id/textViewDp"
        android:layout_width="160dip"
        android:layout_height="wrap_content"
        android:background="#00CC77"
     />
    
    <TextView android:id="@+id/textViewPx"
        android:layout_width="160dip"
        android:layout_height="wrap_content"
        android:background="#00CC77"
     />

</LinearLayout>

同时也定义了几个TextView, 来展示屏幕的宽度,屏幕密度比例 和 屏幕的密度。

public class DipActivity extends Activity{

	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
		float density = displayMetrics.density;
		int densityDpi = displayMetrics.densityDpi;
		int screenWidth = displayMetrics.widthPixels;
		
		setContentView(R.layout.dip_layout);
		
		TextView textViewSw = (TextView)findViewById(R.id.textViewSw);
		textViewSw.setText("screen Width (px):" + screenWidth);
		
		TextView dpView = (TextView)findViewById(R.id.textViewDp);
		dpView.setText("Density :" + density);
		
		TextView pxView = (TextView)findViewById(R.id.textViewPx);
		pxView.setText("Density Dpi : " + String.valueOf(densityDpi));
		
	}
}

然后我们运行代码,看看效果怎么样?如下,上面的是在480*800的模拟器上,下面是在320*480的模拟器上。

Android中 dip 和 px 的关系   

 Android中 dip 和 px 的关系

我们先来看屏幕为480*800的机器,

Button的宽度为160dip的很明显要比160px的要长,事实上,160dip的按钮占据了一半的宽度(240px),而160px的Button,就是160px.

为什么会这样呢?其实就是跟图上展示的Density有关了,我把它称为密度比例,它的值是当前屏幕的dpi (Dot Per Inch,不是dip)跟 160 的一个比例。

在屏幕密度 Density dpi 为240的手机上,密度比例Density = 240 / 160 = 1.5. 

而dip 跟 px 的之间的比例 则为 px = dip * 1.5, 即当我们在布局中设置按钮的宽为160dip时,当它经过系统的换算,展现在屏幕上的已经是像素,而其值就是160 * 1.5 = 240px.

在Android手机中,一般有下面4个级别的屏幕密度,

1)120 - Low 对应的density = 120 / 160 = 0.75

2)160 - Medium 对应的density = 160 / 160 = 1.0 

3)240 - High 对应的density = 240 / 160 = 1.5

4)320 - Extra High 对应的density = 320 / 160 =2.0

这个值可以通过DisplayMetrics来拿到,如下:

DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
float density = displayMetrics.density;
int densityDpi = displayMetrics.densityDpi;
int screenWidth = displayMetrics.widthPixels;
当我们在布局中以dip为单位的时候,中间其实会经过系统的换算,根据不同的屏幕密度,将其转换成对应屏幕的像素,从而达到适应不同屏幕分辨率的问题。

在320*480的机器上,可以看到Density Dpi = 160, 那么其Density = 160/160 = 1.0, 那么160dip 转换成像素就是 160 * 1.0 = 160px. 

所以160dip的按钮跟160px的按钮在屏幕上展现是一样宽的。

综合两个图来看,当我们定义160dip的时候,无论是在上边的机器还是下边的机器,按钮都是占据屏幕的一半宽度,而如果定义成160px的话,则达不到这样的效果。

我想这也就是为什么Android会推荐用dip而不推荐px了,因为不同分辨率的手机屏幕实在是太多了,用像素的话,定死了,真不好看。

而用dip,则系统会去读取屏幕的密度,再根据密度比例来计算真正要展现在屏幕上的像素,效果会好很多。

Android中 dip 和 px 的关系

上一篇:使用jqMobi开发app基础:通过panel添加内容


下一篇:Android 解析JSON