屏幕尺寸密度

Android实战技巧之十:获得屏幕物理尺寸、密度及分辨率

原创  2015年01月13日 21:00:22

大家帮忙喽!

博主参加2014博客之星活动,大家帮忙投票啦!猛击这里


通过程序去了解硬件情况是一件十分有意思的事情。很早我就研究在WM6.5上获得屏幕物理尺寸,但一直没有成功。后来又想要在Android上有所突破,不过在今天之前得到的尺寸都不准确。虽然很多人认为没必要这么较真,因为貌似很多情况下用不到。不过我就当这是一件很有挑战性的事,一定要做到。对,就是这么任性。


源码中android.view包下的Display类提供了很多方法供程序员获得显示相关的信息,通过此类让我们开启了解设备屏幕之旅吧。

一、分辨率
需要注意的原来经常使用的getHeight()与getWidth()已经不推荐使用了,建议使用getSize()来替代。
此方法原型如下:
[java]  view plain  copy
  1. public void getSize(Point outSize) {  
  2.     synchronized (this) {  
  3.         updateDisplayInfoLocked();  
  4.         mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);  
  5.         outSize.x = mTempMetrics.widthPixels;  
  6.         outSize.y = mTempMetrics.heightPixels;  
  7.     }  
  8. }  
参数是一个返回参数,用以返回分辨率的Point,这个Point也比较简单,我们只需要关注x和y这两个成员就可以了。
用法如下:
[java]  view plain  copy
  1. private void getDisplayInfomation() {  
  2.     Point point = new Point();  
  3.     getWindowManager().getDefaultDisplay().getSize(point);  
  4.     Log.d(TAG,"the screen size is "+point.toString());  
  5. }  
结果如下:
[plain]  view plain  copy
  1. D/MainActivity﹕ the screen size is Point(800, 1280)  

此外Display又提供了一个getRealSize方法,原型如下:
[java]  view plain  copy
  1. public void getRealSize(Point outSize) {  
  2.     synchronized (this) {  
  3.         updateDisplayInfoLocked();  
  4.         outSize.x = mDisplayInfo.logicalWidth;  
  5.         outSize.y = mDisplayInfo.logicalHeight;  
  6.     }  
  7. }  

从两个方法的实现上看是有区别的,但是在通常情况下二者的返回值相同。那么差异究竟在哪里,下面做一些实验来验证一下。
首先,我将Acitvity设置不同的theme,比如:
[html]  view plain  copy
  1. android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"  
  2. android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  
结果还是相同的。

接下来将我的Activity父类变成ActionBarActivity,如下:
public class MainActivity extends ActionBarActivity
期望ActionBar会占用一些屏幕,并在程序中动态设置Listview的Item中的图片大小。在机缘巧合之下,
结果验证了在这种情况下,getSize返回的结果变了。
代码如下:
[java]  view plain  copy
  1. private void getDisplayInfomation() {  
  2.     Point point = new Point();  
  3.     getWindowManager().getDefaultDisplay().getSize(point);  
  4.     Log.d(TAG,"the screen size is "+point.toString());  
  5.     getWindowManager().getDefaultDisplay().getRealSize(point);  
  6.     Log.d(TAG,"the screen real size is "+point.toString());  
  7. }  

Log如下:
[plain]  view plain  copy
  1. D/MainActivity﹕ the screen size is Point(800, 1202)  
  2. D/MainActivity﹕ the screen real size is Point(800, 1280)  

如果你不能够轻易复现也不用急,保险起见,为了得到相对正确的信息还是使用getRealSize()吧。
二、屏幕尺寸
设备的物理屏幕尺寸。与几年前不同,目前的手机屏幕已经大到一只手握不下了。标配早已经到了5寸屏时代。
所谓屏幕尺寸指的是屏幕对角线的长度,单位是英寸。
然而不同的屏幕尺寸是可以采用相同的分辨率的,而它们之间的区别在与密度(density)不同。
下面先介绍一下密度的概念,DPI、PPI,最后讲解一下如何根据获得的Display信息去求出屏幕尺寸。这是一个困扰我很久的问题了。
三、屏幕密度
屏幕密度与DPI这个概念紧密相连,DPI全拼是dots-per-inch,即每英寸的点数。也就是说,密度越大,每英寸内容纳的点数就越多。
android.util包下有个DisplayMetrics类可以获得密度相关的信息。
最重要的是densityDpi这个成员,它有如下几个常用值:
[java]  view plain  copy
  1. DENSITY_LOW = 120  
  2. DENSITY_MEDIUM = 160  //默认值  
  3. DENSITY_TV = 213      //TV专用  
  4. DENSITY_HIGH = 240  
  5. DENSITY_XHIGH = 320  
  6. DENSITY_400 = 400  
  7. DENSITY_XXHIGH = 480  
  8. DENSITY_XXXHIGH = 640  

举例如下:
[java]  view plain  copy
  1. private void getDensity() {  
  2.     DisplayMetrics displayMetrics = getResources().getDisplayMetrics();  
  3.     Log.d(TAG,"Density is "+displayMetrics.density+" densityDpi is "+displayMetrics.densityDpi+" height: "+displayMetrics.heightPixels+  
  4.         " width: "+displayMetrics.widthPixels);  
  5. }  

Log如下:
[plain]  view plain  copy
  1. the screen size is Point(1600, 2438)  
  2. the screen real size is Point(1600, 2560)  
  3. Density is 2.0 densityDpi is 320 height: 2438 width: 1600  

有了这些信息,我们是不是就可以计算屏幕尺寸了呢?
首先求得对角线长,单位为像素。
然后用其除以密度(densityDpi)就得出对角线的长度了。
代码如下:
[java]  view plain  copy
  1. private void getScreenSizeOfDevice() {  
  2.     DisplayMetrics dm = getResources().getDisplayMetrics();  
  3.     int width=dm.widthPixels;  
  4.     int height=dm.heightPixels;  
  5.     double x = Math.pow(width,2);  
  6.     double y = Math.pow(height,2);  
  7.     double diagonal = Math.sqrt(x+y);  
  8.   
  9.     int dens=dm.densityDpi;  
  10.     double screenInches = diagonal/(double)dens;  
  11.     Log.d(TAG,"The screenInches "+screenInches);  
  12. }  

Log如下:

[plain]  view plain  copy
  1. 01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2438)  
  2. 01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)  
  3. 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  
  4. 01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.112922229586951  
如Log所见,使用heightPixels得出的值是2483而不是正确的2560.从而使结果9.11反倒跟真实屏幕尺寸很接近。下面用正确的height再算一遍。
[plain]  view plain  copy
  1. 01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2560)  
  2. 01-13 16:39:05.476  17249-17249/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)  
  3. 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  
  4. 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,对其描述是:
[java]  view plain  copy
  1. //The exact physical pixels per inch of the screen in the X/Y dimension.  
屏幕X/Y轴上真正的物理PPI。
Yes!Got it!
为了保证获得正确的分辨率,我还是使用getRealSize去获得屏幕宽和高像素。所以,经过修改,代码如下:
[java]  view plain  copy
  1. private void getScreenSizeOfDevice2() {  
  2.     Point point = new Point();  
  3.     getWindowManager().getDefaultDisplay().getRealSize(point);  
  4.     DisplayMetrics dm = getResources().getDisplayMetrics();  
  5.     double x = Math.pow(point.x/ dm.xdpi, 2);  
  6.     double y = Math.pow(point.y / dm.ydpi, 2);  
  7.     double screenInches = Math.sqrt(x + y);  
  8.     Log.d(TAG, "Screen inches : " + screenInches);  
  9. }  
Log is as follows:
[plain]  view plain  copy
  1. 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。
实例代码如下:
[java]  view plain  copy
  1. //pixel = dip*density;  
  2. private int convertDpToPixel(int dp) {  
  3.     DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
  4.     return (int)(dp*displayMetrics.density);  
  5. }  
  6.   
  7. private int convertPixelToDp(int pixel) {  
  8.     DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
  9.     return (int)(pixel/displayMetrics.density);  
  10. }   

参考:

http://stackoverflow.com/questions/19155559/how-to-get-android-device-screen-size

版权声明:本文为博主原创文章,未经博主允许不得转载。
 
tianzhaixing
  • tianzhaixing
    2017-11-02 16:224楼
  • 博主,你好!
    可以利用PPI,计算拍摄图像中水平放置物体的尺寸么?
u014240069
  • u014240069
    2016-04-02 17:383楼
  • densityDpi是从固定的几个值中取出和真实ppi邻近的一项的值。
    所以,基于densityDpi计算出的物理尺寸全部不准确。
nightcurtis
  • nightcurtis
    2015-06-23 09:472楼
  • android的密度只是一个相对的值,比如小米2s真实的dpi是341,代码获取的是320.用一个不准确的dpi值去求真实的屏幕尺寸? 这个真的不科学

Android获得屏幕分辨率的两种方法

package com.wufen.allapp; import android.os.Bundle; import android.app.Activity; import android...

Android系统信息获取 之十二:获取屏幕分辨率及密度

Android中屏幕分辨率可以有三种方式进行获取,一种是通过WindowManager获取,第二种是通过Resources获取,第三种是Display获取。 可结合具体环境灵活使用。 其中获取的...

做了这件事后,这位程序员月薪从15k变身30k!

闲下来的时候,程序员为了个人成长,和培养核心价值,该怎么规划和学习呢...

Android开发:获取屏幕宽和高的两种方法(px、dip、分辨率之间的关系及px与dip互相转化)

获取屏幕宽和高的两种方法,px、dip、分辨率之间的关系及px与dip互相转化。

Android获取真正准确的分辨率,拒绝那些瞎扯乱混的文章

最近因为android设备分辨率的问题被坑惨了,另一方面,公司的美术团队被我也坑惨了,虽然看起来问题不在我,但是这个锅该我来背,毕竟测试分辨率的代码是我写的。网上到处流传的都是各种getMetrics...

android获取设备屏幕大小的方法

// 通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDi...

AI 工程师职业指南

我们请来商汤、杜邦、声智、希为、58同城、爱因互动、中科视拓、鲁朗软件等公司 AI 技术一线的专家,请他们从实践的角度来解析 AI 领域各技术岗位的合格工程师都是怎样炼成的。

Android开发 获取屏幕宽高及尺寸的方法

// 通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().ge...

Android 获取屏幕尺寸与密度

android中获取屏幕的长于宽,参考了网上有很多代码,但结果与实际不符,如我的手机是i9000,屏幕大小是480*800px,得到的结果却为320*533结果很不靠谱,于是自己写了几行代码,亲测一下...

Android精确获取屏幕尺寸

用下面一段代码就可以精确获取屏幕尺寸 public static double getScreenPhysicalSize(Activity ctx) { DisplayMetri...
  • zz_mm
  • zz_mm
  • 2013年01月04日 09:39
  • 1227

获取手机屏幕密度dpi和对应的资源文件夹

1、首先看一下像素密度对应的Android资源文件夹 dpi范围 密度 0dpi ~ 120dpi ldpi 120dpi ~ 160dpi mdpi 160dpi ~ 240dp...

不同Android版本设备正确获取屏幕分辨率的通用方法

不同Android版本设备正确获取屏幕分辨率的通用方法         谈到android屏幕分辨率,大家都知道,但是怎么正确的获取屏幕的分辨率呢?android2.2\2.3\4.0\4.1使用...

Android获取屏幕分辨率的两种方法及比较

在Android应用开发过程中我们会遇到需要获取屏幕尺寸

Android获取屏幕分辨率的三种方法

在activity中 DisplayMetrics dm = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay()...

Android 获取屏幕分辨率

方法一、     WindowManager manage=getWindowManager();         Display display=manage.getDefaultDisplay(...
  • elfylin
  • elfylin
  • 2010年12月30日 23:06
  • 7894

Android获取屏幕的实际分辨率

于是,获取屏幕实际分辨率的方法是: DisplayMetrics metrics =new DisplayMetrics /** * getRealMetrics - 屏幕的原始尺寸,即包含状态栏...

Android获取屏幕分辨率及DisplayMetrics简介

Android 可设置为随着窗口大小调整缩放比例,但即便如此,手机程序设计人员还是必须知道手机屏幕的边界,以避免缩放造成的布局变形问题。手机的分辨率信 息是手机的一项重要信息,很好的是, ...

Android获取当前设备分辨率

在用Unity制作过程中,遇到要获得设备分辨率的问题,先在文档、网上搜了相关设备分辨率的问题,或者说unity API中没有清晰的说明或者要通过其它方法间接的来获得,但是由于时间关系,就直接用Andr...

Android adb获取屏幕分辨率

获取Android设备屏幕分辨率,可以采用最快捷的方式,使用ADB命令获取即可:打印详细方式: adb shell dumpsys window displays示例: 打印简单方式: adb ...

Android中获取屏幕物理尺寸的方法

第一种方法//获取屏幕宽度 int screenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).g...
  • TTCCAAA
  • TTCCAAA
  • 2015年09月30日 11:11
  • 1313

Android 为什么计算不出准确的屏幕尺寸的原因,及 Android 获得屏幕物理尺寸、密度及分辨率

DPI:dots-per-inch,每英寸的像素数量,也就是说,密度越大,每英寸内容纳的点数就越多。这个值是设备自己决定并写死的。 计算方法:获取到屏幕的分辨率:point.x和point.y,再取...

Android屏幕密度(Density)和分辨率的关系

最近正在做Android的UI设计,故搜集了一些Android上进行UI设计的一些资料,现和各位分享下。首先说说density,density值表示每英寸有多少个显示点,与分辨率是两个不同的概念。An...

在线课程

内容举报
返回顶部

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值