关于Android dp,dip,px,sp你需要知道一些内容

该文档是对android单位的一个简单介绍,同时给出了布局方面的建议

Posted by Robert Zhang on January 16, 2015

dpi、dp和dip区别

1、dpi(dot per inch),即每英寸像素,所有的android设备都会被分成120(low),160(medium),240(high),320(xhigh)四种,后来随着市场上android设备越来越多,google官方又增加了213(Added in API level13),480(Added in API level16),640(Added in API level18),三种dpi。比如320240分辨率的屏幕物理尺寸2英寸1.5英寸,dpi=160;

2、dp或dip(density-independent pixel)逻辑密度计算单位,与像素的换算方式为px=dp*(dpi/160)。

以上是我看到一个认为比较好的介绍。在这个基础上我也记录一下我自己对这个的认识。每部手机屏幕长宽值是固定。相同的屏幕下的像素值越多,越是清晰。宽(长)像素值/宽(长)逻辑密度计算单位,px/dp=density。density =getResources().getDisplayMetrics().density。相信这个公式大家还是很清楚的。没错这个就是我们常用的px,dp换算的方法。我是这样理解这个公式的。我们要确保每个屏幕分辨率下所展示的view效果出入不大,需要根据屏幕的具体分辨率来处理。好比两部手机屏幕大小一样,但是手机分辨率却有差异。一部是800480的,另一部是1280900(这里指的是像素)。代码中设置view的长和宽为80,运行后发现两部手机显示出来的内容不一样。好像1280*900的view要小不少。没错,这就是像素密度不同的结果。值得一提的是代码中设置view的时候,80被定义的单位是px。然而我们希望手机展示出来的效果一样,那有该怎么办呢?没错,我们应该将80的单位理解为dp然后根据不同手机的分辨率密度density来转换成相应的px。这样一来虽然初始化的像素值不同,但展现出来的效果却是我们想要的。这也是屏幕适配的一种解决方案。

在android3.2以前,所有的资源文件都有相应的xhdpi,hdpi,mdpi,ldpi四种文件来对应,android3.2以后,为了提供更精准的对布局文件的控制,可以通过为资源文件(res目录下文件)增加后缀来指定该文件夹里的xml布局文件或color.xml,string.xml是为哪种大小的屏幕使用。

第一种后缀:swdp,如layout-sw600dp, values-sw600dp 这里的sw代表smallwidth的意思,当你所有屏幕的最小宽度都大于600dp时,屏幕就会自动到带sw600dp后缀的资源文件里去寻找相关资源文件,这里的最小宽度是指屏幕宽高的较小值,每个屏幕都是固定的,不会随着屏幕横向纵向改变而改变。

第二种后缀wdp 如layout-w600dp, values-w600dp 带这样后缀的资源文件的资源文件制定了屏幕宽度的大于Ndp的情况下使用该资源文件,但它和swdp不同的是,当屏幕横向纵向切换时,屏幕的宽度是变化的,以变化后的宽度来与N相比,看是否使用此资源文件下的资源。

第三种后缀hdp 如layout-h600dp, values-h600dp 这个后缀的使用方式和wdp一样,随着屏幕横纵向的变化,屏幕高度也会变化,根据变化后的高度值来判断是否使用hdp ,但这种方式很少使用,因为屏幕在纵向上通常能够滚动导致长度变化,不像宽度那样基本固定,因为这个方法灵活性不是很好,google官方文档建议尽量少使用这种方式。

ViewGroup简介(引用他处)

1、ViewGroup的职责

ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等;当然还有margin等;于是乎,ViewGroup的职能为:给childView计算出建议的宽和高和测量模式;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。

2、View的职责

View的职责,根据测量模式和ViewGroup给出的建议的宽和高,计算出自己的宽和高;同时还有个更重要的职责是:在ViewGroup为其指定的区域内绘制自己的形态。

3、ViewGroup和LayoutParams之间的关系

大家可以回忆一下,当在LinearLayout中写childView的时候,可以写layout_gravity,layout_weight属性;在RelativeLayout中的childView有layout_centerInParent属性,却没有layout_gravity,layout_weight,这是为什么呢?这是因为每个ViewGroup需要指定一个LayoutParams,用于确定支持childView支持哪些属性,比如LinearLayout指定LinearLayout.LayoutParams等。如果大家去看LinearLayout的源码,会发现其内部定义了LinearLayout.LayoutParams,在此类中,你可以发现weight和gravity的身影。

4、View的3种测量模式

上面提到了ViewGroup会为childView指定测量模式,下面简单介绍下三种测量模式:

  • EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;

  • AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;

  • UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

注:上面的每一行都有一个一般,意思上述不是绝对的,对于childView的mode的设置还会和ViewGroup的测量mode有一定的关系;当然了,这是第一篇自定义ViewGroup,而且绝大部分情况都是上面的规则,所以为了通俗易懂,暂不深入讨论其他内容。

5、从API角度进行浅析

上面叙述了ViewGroup和View的职责,下面从API角度进行浅析。

View的根据ViewGroup传人的测量值和模式,对自己宽高进行确定(onMeasure中完成),然后在onDraw中完成对自己的绘制。

ViewGroup需要给View传入view的测量值和模式(onMeasure中完成),而且对于此ViewGroup的父布局,自己也需要在onMeasure中完成对自己宽和高的确定。此外,需要在onLayout中完成对其childView的位置的指定。

ps: 以上为个人帮助记忆的note,若有不当的理解希望不会误导他人。 ps2:部分内容有借用,没有贴出链接是因为我也不清楚他是否为原帖,请原帖主人多见谅。