Android 丨 获取屏幕尺寸与密度

Posted 左郁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 丨 获取屏幕尺寸与密度相关的知识,希望对你有一定的参考价值。

近期遇到一个问题,我的地图浮标图片在WVGA手机上正好,在QVGA上就显的太大,所以我要根据屏幕的不同调整浮标的大小使其在QVGA大小合适。有的同事提出了依据分辨率来区分不同的屏幕,但是单WVGA就支持好几种不同的分辨率,QVGA又支持好几种。。。而且更神奇的时候,有时候,通过代码获取屏幕分辨率竟然得到了 320 x 427 ,android文档是不支持这种分辨率的,所以依据分辨率来区分不同的屏幕是行不通的。还好通过仔细研读文档,“各种VGA的density是不同的,(hdpi: 240 , ldpi: 120 , mdpi: 160 , xhdpi: 320)”,所以只要求出不同屏幕的density,就可以知道该手机属于的屏幕类型。

 

首先是几个基本概念:

1.屏幕尺寸Screen size

即显示屏幕的实际大小,按照屏幕的对角线进行测量。

为简单起见,Android把所有的屏幕大小分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large).

应用程序可以为这四种尺寸分别提供不同的自定义屏幕布局-平台将根据屏幕实际尺寸选择对应布局进行渲染,这种选择对于程序侧是透明的。

2.屏幕长宽比Aspect ratio

长宽比是屏幕的物理宽度与物理高度的比例关系。应用程序可以通过使用限定的资源来为指定的长宽比提供屏幕布局资源。

3.屏幕分辨率Resolution

在屏幕上显示的物理像素总和。需要注意的是:尽管分辨率通常用宽x高表示,但分辨率并不意味着具体的屏幕长宽比。

在Andorid系统中,应用程序不直接使用分辨率。

4.密度Density

根据像素分辨率,在屏幕指定物理宽高范围内能显示的像素数量。

在同样的宽高区域,低密度的显示屏能显示的像素较少,而高密度的显示屏则能显示更多的像素。

屏幕密度非常重要,因为其它条件不变的情况下,一共宽高固定的UI组件(比如一个按钮)在在低密度的显示屏上显得很大, 而在高密度显示屏上看起来就很小。

为简单起见,Android把所有的屏幕分辨率也分为四种尺寸:小,普通,大,超大(分别对应:small, normal, large, and extra large).

应用程序可以为这四种尺寸分别提供不同的资源-平台将透明的对资源进行缩放以适配指定的屏幕分辨率。

密度无关的像素( DIP ) 
指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。 
一个与密度无关的像素,在逻辑尺寸上,与一个位于像素密度为 160DPI的屏幕上的像素是一致的,这也是Android平台所假定的默认显示设备。在运行的时候,平台会以目标屏幕的密度作为基准,“透明地”处理所 有需要的DIP缩放操作。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式: pixels = dips * (density / 160)。举个例子,在 DPI为 240的屏幕上, 1个 DIP等于 1.5个物理像素。我们强烈推荐你用 DIP来定义你程序的界面布局,因为这样可以保证你的 UI在各种分辨率的屏幕上都可以正常显示

    在一个Activity的onCreate方法中,写入如下代码:
        DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        int width = metric.widthPixels;  // 屏幕宽度(像素)
        int height = metric.heightPixels;  // 屏幕高度(像素)
        float density = metric.density;  // 屏幕密度(0.75 / 1.0 / 1.5)
        int densityDpi = metric.densityDpi;  // 屏幕密度DPI(120 / 160 / 240)
     但是,需要注意的是,在一个低密度的小屏手机上,仅靠上面的代码是不能获取正确的尺寸的。比如说,一部240x320像素的低密度手机,如果运行上述代码,获取到的屏幕尺寸是320x427。因此,研究之后发现,若没有设定多分辨率支持的话,Android系统会将240x320的低密度(120)尺寸转换为中等密度(160)对应的尺寸,这样的话就大大影响了程序的编码。所以,需要在工程的AndroidManifest.xml文件中,加入supports-screens节点,具体的内容如下:
        <supports-screens
            android:smallScreens="true"
            android:normalScreens="true"
            android:largeScreens="true"
            android:resizeable="true"
            android:anyDensity="true"/>
    这样的话,当前的Android程序就支持了多种分辨率,那么就可以得到正确的物理尺寸了。    
	// 获取屏幕密度(方法1)  
	int screenWidth  = getWindowManager().getDefaultDisplay().getWidth();       // 屏幕宽(像素,如:480px)  
	int screenHeight = getWindowManager().getDefaultDisplay().getHeight();      // 屏幕高(像素,如:800p)  
	  
	Log.e(TAG + "  getDefaultDisplay", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);  
	  
	  
	// 获取屏幕密度(方法2)  
	DisplayMetrics dm = new DisplayMetrics();  
	dm = getResources().getDisplayMetrics();  
	  
	float density  = dm.density;        // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)  
	int densityDPI = dm.densityDpi;     // 屏幕密度(每寸像素:120/160/240/320)  
	float xdpi = dm.xdpi;             
	float ydpi = dm.ydpi;  
	  
	Log.e(TAG + "  DisplayMetrics", "xdpi=" + xdpi + "; ydpi=" + ydpi);  
	Log.e(TAG + "  DisplayMetrics", "density=" + density + "; densityDPI=" + densityDPI);  
	  
	screenWidth  = dm.widthPixels;      // 屏幕宽(像素,如:480px)  
	screenHeight = dm.heightPixels;     // 屏幕高(像素,如:800px)  
	  
	Log.e(TAG + "  DisplayMetrics(111)", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);  
	  
	  
	  
	// 获取屏幕密度(方法3)  
	dm = new DisplayMetrics();  
	getWindowManager().getDefaultDisplay().getMetrics(dm);  
	  
	density  = dm.density;      // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)  
	densityDPI = dm.densityDpi;     // 屏幕密度(每寸像素:120/160/240/320)  
	xdpi = dm.xdpi;           
	ydpi = dm.ydpi;  
	  
	Log.e(TAG + "  DisplayMetrics", "xdpi=" + xdpi + "; ydpi=" + ydpi);  
	Log.e(TAG + "  DisplayMetrics", "density=" + density + "; densityDPI=" + densityDPI);  
	  
	int screenWidthDip = dm.widthPixels;        // 屏幕宽(dip,如:320dip)  
	int screenHeightDip = dm.heightPixels;      // 屏幕宽(dip,如:533dip)  
	  
	Log.e(TAG + "  DisplayMetrics(222)", "screenWidthDip=" + screenWidthDip + "; screenHeightDip=" + screenHeightDip);  
	  
	screenWidth  = (int)(dm.widthPixels * density + 0.5f);      // 屏幕宽(px,如:480px)  
	screenHeight = (int)(dm.heightPixels * density + 0.5f);     // 屏幕高(px,如:800px)  
	  
	Log.e(TAG + "  DisplayMetrics(222)", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);  
	


  重中之重: density值表示每英寸有多少个显示点,与分辨率是两个不同的概念:

Android主要有以下几种屏:

QVGA和WQVGA屏density=120;

HVGA屏density=160;

WVGA屏density=240;

下面以480dip*800dip的WVGA(density=240)为例,详细列出不同density下屏幕分辨率信息:

当density=120时 屏幕实际分辨率为240px*400px (两个点对应一个分辨率)
状态栏和标题栏高各19px或者25dip
横屏是屏幕宽度400px 或者800dip,工作区域高度211px或者480dip
竖屏时屏幕宽度240px或者480dip,工作区域高度381px或者775dip

density=160时 屏幕实际分辨率为320px*533px (3个点对应两个分辨率)
状态栏和标题栏高个25px或者25dip
横屏是屏幕宽度533px 或者800dip,工作区域高度295px或者480dip
竖屏时屏幕宽度320px或者480dip,工作区域高度508px或者775dip

density=240时 屏幕实际分辨率为480px*800px (一个点对于一个分辨率)
状态栏和标题栏高个38px或者25dip
横屏是屏幕宽度800px 或者800dip,工作区域高度442px或者480dip
竖屏时屏幕宽度480px或者480dip,工作区域高度762px或者775dip

apk的资源包中,当屏幕density=240时使用hdpi标签的资源
当屏幕density=160时,使用mdpi标签的资源
当屏幕density=120时,使用ldpi标签的资源。
不加任何标签的资源是各种分辨率情况下共用的。
建议:布局时尽量使用单位dip,少使用px。

device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。

 

 

以上是关于Android 丨 获取屏幕尺寸与密度的主要内容,如果未能解决你的问题,请参考以下文章

确定多个 android 屏幕尺寸/密度的图像尺寸

Android 屏幕适配屏幕适配基础概念 ① ( Android 与 iOS 屏幕宽高比种类 | 屏幕像素密度 DPI )

在 Android 上针对不同的屏幕尺寸和密度重用可绘制图像

Android应用程序支持不同屏幕(尺寸密度)

Android 屏幕尺寸数据库

手机屏幕密度等级和屏幕逻辑尺寸