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