33.Android 开发:屏幕相关数据
术语解析
像素(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作为长度单位,在一个大屏幕低分屏上可以正常触控的按钮,换到一个一个小屏幕高分屏上可能很难按到(因为物理尺寸变小了,手指头可不能跟着变小),所以需要使用一个和屏幕参数无关的单位,维持交互控件的物理尺寸。
获取屏幕分辨率
方式1:
# 像素宽
int width = context.getResources().getDisplayMetrics().widthPixels;
# 像素高
int height = context.getResources().getDisplayMetrics().heightPixels;
方式2:
//获取手机屏幕分辨率的类
private DisplayMetrics displayMetrics;
displayMetrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
# 像素宽
int width = displayMetrics.widthPixels;
# 像素高
int height = displayMetrics.heightPixels;
注意:getMetrics()和getRealMetrics()
getMetrics()这种方法广为流传,百度一下但是这种方法有一个弊端,具体原因为getMetrics()获取到的屏幕信息在android4.4后会忽略底部的虚拟按键的高度。所以此时该用getRealMetrics()。
getRealMetrics()和getMetrics()获取到的屏幕信息差别只在于widthPixels或heightPixels的值是否去除虚拟键所占用的像素,和是否全屏和沉浸模式无关。
具体到我的问题就是用getMetrics()获取到的是1280x672,而用getRealMetrics()获取到的就是正确的1280x720。2个方法仅仅相差一个Real,然而结果却完全不同,而网络上大部分都是前者,仅仅是今天我才发现有一篇文章提到了getRealMetrics(),并解释了二者的区别。
术语解析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。
px-dp 缩放因子(像素密度)
方式1:
float density = context.getResources().getDisplayMetrics().density;
方式2:
displayMetrics = new DisplayMetrics();
// dp缩放因子
float density = displayMetrics.density;