Android屏幕宽高获取和尺寸单位

原文网址:http://xiaoyaozjl.iteye.com/blog/2178415

获取屏幕参数代码:

Java代码  收藏代码
  1. DisplayMetrics metric = new DisplayMetrics();  
  2. //API 17之后使用,获取的像素宽高包含虚拟键所占空间,在API 17之前通过反射获取  
  3. context.getWindowManager().getDefaultDisplay().getRealMetrics(metric);  
  4. //获取的像素宽高不包含虚拟键所占空间  
  5. //context.getWindowManager().getDefaultDisplay().getMetrics(metric);  
  6. int width = metric.widthPixels;  // 宽度(像素)  
  7. int height = metric.heightPixels;  // 高度(像素)  
  8. float density = metric.density;  // dp缩放因子  
  9. int densityDpi = metric.densityDpi;  // 广义密度  
  10. float xdpi = metric.xdpi;//x轴方向的真实密度  
  11. float ydpi = metric.ydpi;//y轴方向的真实密度  

 

getRealMetrics()和getMetrics()获取到的屏幕信息差别只在于widthPixels或heightPixels的值是否去除虚拟键所占用的像素,和是否全屏和沉浸模式无关。

 

屏幕高度值包含了状态栏的像素,非沉浸模式下真实的Activity高度需要减去状态栏的高度。获取状态栏高度代码:

Java代码  收藏代码
  1. private int getStatusBarHeight() {  
  2.     Rect rect = new Rect();  
  3.     getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);  
  4.     return rect.top;  
  5. }  

 

屏幕参数Width和Height的值和屏幕方向有关,另外4个值和屏幕方向无关。

 

    术语解析1:

像素(Pixel:屏幕绘制的最小单位,无论在开发时使用什么尺寸单位,最终都需要转为像素。下简称px。

密度无关像素(Density independent pixel,简称dip/dp:简单来说是一个物理尺寸单位,宽高具有相同dp值的widget在不同屏幕上的物理尺寸是相同的(但实际上可能是近似,因为Android设备使用广义密度而不是真实密度,下面会讲述),和屏幕尺寸以及分辨率没有关系。下简称dp。

屏幕大小(Screen size):如果没特别说明,屏幕大小是指其对角线长度,单位为英寸。

屏幕密度(Dots per inch,简称Dpi):屏幕每英寸上有多少个px点。计算公式:sqrt(widthPixels *widthPixels + heightPixels * heightPixels) / screenSize

 

为什么Android要使用dp而不是传统的px作为widget长度单位:

        Android的主要交互是触控,而人的手指头大小变化范围比较小。如果以px作为长度单位,在一个大屏幕低分屏上可以正常触控的按钮,换到一个一个小屏幕高分屏上可能很难按到(因为物理尺寸变小了,手指头可不能跟着变小),所以需要使用一个和屏幕参数无关的单位,维持交互控件的物理尺寸。
 
    术语解析2:
广义密度(Generalized density):从上面屏幕密度的计算公式可知,通过更改分辨率或者屏幕尺寸可以搞出无数种真实屏幕密度,不同的屏幕密度意味着,绘制相同的物理尺寸的widget要使用的px数是不一样的。假定要让一张图片在10个屏幕密度不一样的设备上以相同物理尺寸显示(不使用动态缩放),那么开发者需要准备10张px面积不同的图片以获得最佳显示效果,显然这是不可接受的。对此Android的解决方案是牺牲widget在物理尺寸上的一致性,在不同密度的设备上widget物理尺寸只是近似而不是相同,换取适配工作量的降低。
具体的做法:将一定范围的屏幕密度的设备视为一个特定的密度,比如屏幕密度在240左右的设备视为高密度(hdpi),在320左右的视为超高密度(xhdpi)等。注意的是,在两个广义密度之间并没有明确的边界值,屏幕具体属于何种广义密度由系统决定而不是由真实密度决定,系统在进行绘制换算时也只会使用广义密度。下简称density。

dp缩放因子:每个dp对应多少个px。这个值在Android系统的变量命名也是density,但实际上和屏幕密度是两回事,所以我称之为scale factor。先说说这个值的来源,Android系统规定在广义密度为160(mdpi)的设备上1dp=1px,这是一个定值。对于密度为320(xhdpi)的设备,后者每英寸像素点为前者的320/160=2倍。在前者使用1个像素绘制的物体,在后者需要使用4个像素(2*2)绘制,对于用户来说它的物理大小才是相同的,那么显然,对于后者来讲1dp=2px。换句话说,dp缩放因子 = density / 160,同时可以推出公式px = dp * dp缩放因子 = dp * (density / 160) 。下简称factor。
 
    从上面延伸的公式:
屏幕的dp数:
widthDps = widthPixels * 160 / density = widthPixels / factor
heightDps = heightPixels * 160 / density = heightPixels / factor

维持widget在不同密度屏幕的比例:
所谓维持比例也就是说widget尺寸和屏幕尺寸的比值相同,有
WidgetWidthDpA / ScreenWidthDpA = WidgetWidthDpB / ScreenWidthDpB ,那么
WidgetWidthDpB = WidgetWidthDpA * ScreenWidthDpB / ScreenWidthDpA ,或
WidgetWidthDpB = WidgetWidthDpA * rate
其中rate = (screenWidthPixelsB / densityB) / (screenWidthPixelsA / densityA)
实际使用中,因为这个比值不仅和广义密度比有关并且和分辨率比有关,要完整适配所有设备比较困难,一般推荐使用空白区变长的方法完成适配而不是维持画面比例。
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页