android中有很多未知的“路”,只有走好每一步,才有可能找到捷径!!!
1. 获取 android 设备屏幕大小
在说具体的操作方法之前,我们先了解一下几个知识点,下面都是都是自己的语言描述,与专业术语有差异。
a. 像素与分辨率
像素,指的是一定区域类(矩形区域)横向、纵向上点的乘积的结果,单位是 pixel.
分辨率,指的是一定区域类(矩形区域)横向、纵向上点的乘积如 1280×800.
b. 密度
在android中,密度叫做 density,其单位是 dpi(dot per inch),意思是每英寸上面的点数。
关于 dpi 的分类,可以参考:
官方推荐是,像素统一使用 dip,字体统一使用 sp 。
dip 与 px 之间的换算关系是:
pixs =dips * (densityDpi/160),也就是说当 densityDpi=160 时,1dip=1px
关于单位换算源码位于:
\frameworks\base\core\java\android\util\TypedValue.java
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
c. 屏幕的大小与设备分辨率计算
这里说的“屏幕的大小”,指的是设备实在的物理尺寸。
首先区别,设备的 物理尺寸 和 分辨率,
比如 5寸 手机分辨率可以是 480*320,那么 7寸 手机分辨率也可以是 480*320,
但是 5寸 设备显示效果肯定比 7寸 设备要好要清晰。
(1). 计算物理尺寸
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width= dm.widthPixels;
int height= dm.heightPixels;
Log.d("mark", "screen's width * height = " + width + "*" + height);
打印结果:
screen's width * height = 240*320
下面再说一种网上流传的计算设备屏幕大小的方式:
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Log.d("mark", "screen's width * height = " + width + "*" + height);
我的手机测试,实际情况符合!
但是分辨率不可能这么高的。
上面的两种方式当且仅当屏幕密度为 1 的时候,
可以计算分辨率或者物理尺寸,否则只可以计算物理尺寸,切记
往下看。。。
(2).计算分辨率
最好,你在 manifest.xml 里面加入类似下面的配置:
<uses-sdk
android:minSdkVersion="6"
android:targetSdkVersion="10" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" />
设备分为高密度、中密度以及低密度的类型,其计算方法是:
屏幕宽(screenWidth) = 横向像素点数 × 密度
屏幕高(screenHeight) = 纵向像素点数 × 密度
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int widthPixels= dm.widthPixels;
int heightPixels= dm.heightPixels;
float density = dm.density;
int dpi = dm.densityDpi;
Log.d("mark", "other info about device is density = " + density + ", and the dpi is " + dpi);
int screenWidth = (int) (widthPixels * density);
int screenHeight =(int) (heightPixels * density) ;
Log.d("mark", "screen's width * height = " + screenWidth + "*" + screenHeight + " and the density = " + density);
other info about device is density = 0.75, and the dpi is 120
screen's width * height = 180*240 and the density = 0.75
打印结果就是我手机的分辨率大小。
从打印信息上面可以看出我的手机是低密度的(ldpi),其密度值是 0.75。
关于 density 的值一般是1.0、0.5、0.75、1.5等。
ok,详细信息参看:SDK/docs/guide/practices/screens_support.html
2. layout-320x240 到底指什么
在 android 中,layout-320x240,还有 drawable-320x240 到底指的是什么?
测试还是以我自己的手机为例,下面是测试工程的 res 文件内容
分别建立 drawable-ldpi-320x240、layout-320x240、values-320x240 文件夹。
在 drawable-ldpi-320x240 里面放置一个 app_icon,该图片不同于 drawable 等其它文件夹图标。
在 layout-320x240 放置与 layout 里面相同的布局文件。
这个布局文件是 activity 启动加载的,本质就是加载一个textview。
在 values-320x240 放置与 values 里面相同的 string.xml 文件,只是修改了 textview 显示的字符串。
<string name="java">java or android ?</string>
而 values 里面是 <string name="java">Hello World</string>
我使用如下代码
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int sw = dm.widthPixels;
int sh = dm.heightPixels;
System.out.println("sw * sh = " + sw + " * " + sh);
获取手机屏幕大小是 320x240,所以上面文件夹后缀都是 320x240.
运行程序之后,发现调用资源文件都是后缀 320x240 文件夹的东西。
这就说明,320x240 表示的是手机屏幕物理尺寸大小,
不是分辨率大小,我手机的分辨率是 180 * 240。
3. 改变 android 设备屏幕方向
android手机在改变屏幕方向(横屏与竖屏互相切换)的时候,会多次调用onCreate()方法,以及onPause()、onStop()、onDestroy()方法,然后重新调用onCreate()、onStart()、onResume()方法使该activity重新展现在我们面前。
利用这种特性可以实现某些特殊的效果,但是在大多数情况下,我们还是想让它只调用一次onCreate()方法。因为onCreate()方法一般用来做一些初始化的工作,毕竟没有多少人希望初始化工作会一次又一次的进行着。特别是你的app有多个activity,如果在改变屏幕方向(横屏与竖屏互相切换)的时候onCreate()方法总是在调用,那么这可能就是一场噩梦!!下面介绍改变这中现状的方法。主要两个步骤!!
<1>修改manifest.xml文件
添加如下代码,即可
完整示例如下:
这样,切换屏幕时就不会多次调用onCreate()方法,从而不会影响activity生命周期。那么,既然不会多次调用onCreate()方法,系统又是调用哪个方法呢?接着看.....
<2>覆写Activity的onConfigurationChanged()方法
如果你想在屏幕方向改变时,做一些操作必须覆写onConfigurationChanged()方法。在该方法中我们可以添加自己的代码,主要有两中写法,如下:
或者:
这两种方式,打印结果:
但是这是在模拟器上面测试的结果,在真机上测试结果不一样。
还有一点需要注意:super.onConfigurationChanged(newConfig);必须写,否则报异常!
异常信息:
说明要调用父类Activity的onConfigurationChanged()方法。
看一下Activity的onConfigurationChanged()方法源码:
可以看出,调用了抽象类Window的onConfigurationChanged()方法。看源码如下:
4. 固定屏幕方向
从上面我们知道,当改变设备或者模拟器的屏幕方向时,相应的显示模式也将根据变化匹配现有的情况,这样,Activity
根据不同的模式(Portrait和Landscape)重新调整视图的显示方式。如果你想让你的视图一直处于某一个固定方向,可以
在Manifest里为相应的Activity添加Android:screenOrientation属性,并赋予”portrait”或”Landscape”属性。
5. 跟 Camera 有关
使用过 android 的照相机的 api 的朋友知道,如果不做处理,画面是不会随着手机的方向变化而变化。
其实改变这种现状也很简单,一句代码的事:
记住:
这种方法不会禁止应用程序多次调用onCreate()方法,所以你需要按照上面的方法去禁止这种现象发生,如果你需要的话。
对应的 getRequestedOrientation( )方法返回屏幕方向的数据,如果没有指定屏幕方向的话,调用 getRequestedOrientation( )
方法会返回 -1(SCREEN_ORIENTATION_UNSPECIFIED),表示没有指定。
如果你在 manifest.xml 或者代码中使用 setRequestedOrientation() 方法设置了屏幕方向的话,会返回对应数据。
具体参数可以查看ActivityInfo类的常量。