(转)获得屏幕物理尺寸、密度及分辨率

转自:http://wiki.jikexueyuan.com/project/android-actual-combat-skills/acquring-screen-physical-size-density-and-resolution.html

// 获取屏幕密度(在Context环境下,比如在Activity中执行这些代码或者传入Context对象去获得DisplayMetrics)
DisplayMetrics dm = getResources().getDisplayMetrics();
// getWindowManager().getDefaultDisplay().getMetrics(dm);

float density = dm.density;       // 屏幕密度(像素比例:0.75/1.0/1.5/2.0,3.0,4等)
int densityDPI = dm.densityDpi;   // 屏幕密度(这里是系统密度)(每寸像素:120/160/240/320,480,640等)

// 这两个是水平和垂直方向上的dpi,如果要计算水平和垂直方向上的实际dp值,可以通过后面`屏幕的宽高差异`中的内容计算。不过你倒是可以通过这两个值大致计算屏幕的宽和高的英寸
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" + "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);

一、分辨率

/**
 * 获取屏幕分辨率
 */
private void getDisplayInfomation() {  
    Point point = new Point();  
    
    getWindowManager().getDefaultDisplay().getSize(point);  
    Log.d(TAG,"the screen size is "+point.toString());  
    
    getWindowManager().getDefaultDisplay().getRealSize(point);  
    Log.d(TAG,"the screen real size is "+point.toString());  
}

getSize和主题有关的。保险起见,为了得到相对正确的信息还是使用 getRealSize() 吧。

二、屏幕密度

屏幕密度与 DPI 这个概念紧密相连,DPI 全拼是 dots-per-inch,即每英寸的点数。也就是说,密度越大,每英寸内容纳的点数就越多。 android.util 包下有个 DisplayMetrics 类可以获得密度相关的信息。

最重要的是 densityDpi 这个成员,它有如下几个常用值:

    DENSITY_LOW = 120  
    DENSITY_MEDIUM = 160  // 默认值  
    DENSITY_TV = 213      // TV专用  
    DENSITY_HIGH = 240  
    DENSITY_XHIGH = 320  
    DENSITY_400 = 400  
    DENSITY_XXHIGH = 480  
    DENSITY_XXXHIGH = 640 

// 举例如下:
private void getDensity() {  
    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();  
    
    Log.d(TAG,"Density is " + displayMetrics.density + " densityDpi is " + displayMetrics.densityDpi + " height: " + displayMetrics.heightPixels +  
        " width: " + displayMetrics.widthPixels);  
}

// Log 如下:
    the screen size is Point(1600, 2438)  
    the screen real size is Point(1600, 2560)  
    Density is 2.0 densityDpi is 320 height: 2438 width: 1600  

有了这些信息,我们是不是就可以计算屏幕尺寸了呢?首先求得对角线长,单位为像素。然后用其除以密度(densityDpi)就得出对角线的长度了。

    // 代码如下:
    private void getScreenSizeOfDevice() {  
        DisplayMetrics dm = getResources().getDisplayMetrics();  
        int width = dm.widthPixels;  
        int height = dm.heightPixels;  
        double x = Math.pow(width, 2);  
        double y = Math.pow(height, 2);  
        double diagonal = Math.sqrt(x + y);  

        int dens = dm.densityDpi;  
        double screenInches = diagonal / (double) dens;  
        Log.d(TAG, "The screenInches " + screenInches);  
    }  

    // Log 如下:
    01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2438)  
    01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)  
    01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ Density is 2.0 densityDpi is 320 height: 2438 width: 1600 xdpi 338.666 ydpi 338.666  
    01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.112922229586951  

    如 Log 所见,使用 heightPixels 得出的值是2483而不是正确的2560.从而使结果9.11反倒跟真实屏幕尺寸很接近。下面用正确的 height 再算一遍。

    01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2560)  
    01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)  
    01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ Density is 2.0 densityDpi is 320 height: 2560 width: 1600 xdpi 338.666 ydpi 338.666  
    01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.433981132056605  

结果是9.43英寸,而真实值是8.91.如果再换一个设备,那么值差的更多。说明上面的计算是错误的。

那么错在哪里呢?densityDpi 是每英寸的点数(dots-per-inch)是打印机常用单位(因而也被称为打印分辨率),而不是每英寸的像素数。下面引出 PPI 这个概念。

三、PPI

Pixels per inch,这才是我要的每英寸的像素数(也被称为图像的采样率)。有了这个值,那么根据上面的公式就可以求导出屏幕的物理尺寸了。 还好 DisplayMetrics 有两个成员是 xdpi 和 ydpi,对其描述是:

The exact physical pixels per inch of the screen in the X/Y dimension.  

屏幕 X/Y 轴上真正的物理 PPI。

Yes!Got it!

为了保证获得正确的分辨率,我还是使用 getRealSize 去获得屏幕宽和高像素。所以,经过修改,代码如下:

private void getScreenSizeOfDevice2() {  
    Point point = new Point();  
    getWindowManager().getDefaultDisplay().getRealSize(point);  
    DisplayMetrics dm = getResources().getDisplayMetrics();  
    double x = Math.pow(point.x/ dm.xdpi, 2);  
    double y = Math.pow(point.y / dm.ydpi, 2);  
    double screenInches = Math.sqrt(x + y);  
    Log.d(TAG, "Screen inches : " + screenInches);  
} 
 
// Log is as follows:
01-13 16:58:50.142  17249-17249/com.linc.listviewanimation D/MainActivity﹕ Screen inches : 8.914015757534717  

四、DIP

注意不要与上面的 DPI 混淆,这个 DIP 是 Density Independent Pixel,直译为密度无关的像素。我们在布局文件中使用的 dp/dip 就是它。官方推荐使用 dp 是因为它会根据你设备的密度算出对应的像素。

公式为:pixel = dip*density

需要注意的是,我们在 Java 代码中对控件设置宽高是不可以设置单位的,而其自带的单位是像素。所以如果动态修改控件大小时,我们的任务就来了,那就是将像素转换为 dp。

实例代码如下:

    // pixel = dip * density;  
    private int convertDpToPixel(int dp) {  
        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
        return (int) (dp * displayMetrics.density);  
    }  

    private int convertPixelToDp(int pixel) {  
        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
        return (int) (pixel / displayMetrics.density);  
    }  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容