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

转自: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);  
    }  

你可能感兴趣的:((转)获得屏幕物理尺寸、密度及分辨率)