一、基本概念
参考
关于Android设备屏幕大小及密度的系统参数类
Android中px dpi dip density densityDpi 的相关说明
dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算(终结版)
Px(Pixel像素)
不同设备显示效果相同。这里的“相同”是指像素数不会变,比如指定UI长度是100px,那不管分辨率是多少UI长度都是100px。也正是因为如此才造成了UI在小分辨率设备上被放大而失真,在大分辨率上被缩小。
Screen Size(屏幕尺寸)
一般所说的手机屏幕大小如1.6英寸、1.9英寸、2.2英寸,都是指的对角线的长度,而不是手机面积。我们可以根据勾股定理获取手机的宽和长,当然还有面积。
Resolution(分辨率)
指手机屏幕垂直和水平方向上的像素个数。比如分辨率是480*320,则指设备垂直方向有480个像素点,水平方向有320个像素点。
Dpi(dots per inch像素密度)
dpi是密度,即屏幕每英寸所包含的像素数。比如一个手机屏幕宽2英寸长3英寸,分辨率320480,则密度是160dpi.*
float xdpi = getResources().getDisplayMetrics().xdpi;//获取屏幕密度值
安卓规定,在160dpi屏幕上,1dp等于1px.这样在160dpi屏幕上指定的1dp宽度按钮,到了320dpi屏幕,宽度自动变成2px,保持了所占屏幕比例。
注意:该值对应于DisplayMetrics类中属性densityDpi的值。
Density(密度)
density其实是没单位的,他就是一个比例值,也可以叫缩放系数,值为 densityDpi/160。常见取值 1.5 , 1.0 。
dpi的单位是 像素/英寸,比较符合物理上面的密度定义,密度不都是单位度量的值么,所以我更喜欢把dpi叫像素密度,简称密度,density还是就叫density。
注意:该值对应于DisplayMetrics类中属性density的值。
density | densityDpi |
---|---|
1 | 160 |
1.5 | 240 |
2 | 320 |
3 | 480 |
3.5 | 560 |
4 | 640 |
Dip(Device-independent pixel,设备独立像素)
同dp,可作长度单位,不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。dip和具体像素值的对应公式是dip值 =设备密度/160* pixel值,可以看出在dpi(像素密度)为160dpi的设备上1px=1dip
Sp(ScaledPixels放大像素)
主要用于字体显示(best for textsize)。根据 google 的建议,TextView 的字号最好使用 sp 做单位,而且查看TextView的源码可知 Android 默认使用 sp 作为字号单位。
类似px,传统的pt是磅数,1磅等于1/72英寸,pt一般作为字体单位来使用。
<pre>
/**
- 系统参数类
- @author wader
*/
public class MySystemParams {
private final String TAG = "SystemParams";
private static MySystemParams params;
public int screenWidth;// 屏幕宽度,单位为px
public int screenHeight;// 屏幕高度,单位为px
public int densityDpi;// 屏幕密度,单位为dpi
public float scale;// 缩放系数,值为 densityDpi/160
public float fontScale;// 文字缩放系数,同scale
public final static int SCREEN_ORIENTATION_VERTICAL = 1; // 屏幕状态:横屏
public final static int SCREEN_ORIENTATION_HORIZONTAL = 2; // 屏幕状态:竖屏
public int screenOrientation = SCREEN_ORIENTATION_VERTICAL;// 当前屏幕状态,默认为竖屏
/**
- 私有构造方法
- @param activity
*/
private MySystemParams(Activity activity) {
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
densityDpi = dm.densityDpi;
scale = dm.density;
fontScale = dm.scaledDensity;
screenOrientation = screenHeight > screenWidth ? SCREEN_ORIENTATION_VERTICAL
: SCREEN_ORIENTATION_HORIZONTAL;
}
/**
- 获取实例
- @param activity
- @return
*/
public static MySystemParams getInstance(Activity activity) {
if (params == null) {
params = new MySystemParams(activity);
}
return params;
}
/**
- 获取一个新实例
- @param activity
- @return
*/
public static MySystemParams getNewInstance(Activity activity) {
if (params != null) {
params = null;
}
return getInstance(activity);
}
/**
- 参数信息
*/
public String toString() {
return TAG
+ ":[screenWidth: "
+ screenWidth
+ " screenHeight: "
+ screenHeight
+ " scale: "
+ scale
+ " fontScale: "
+ fontScale
+ " densityDpi: "
+ densityDpi
+ " screenOrientation: "
+ (screenOrientation == SCREEN_ORIENTATION_VERTICAL ? "vertical"
: "horizontal") + "]";
}
}
</pre>
二、屏幕适配
参考
android 屏幕适配
Android屏幕适配全攻略(最权威的官方适配指导)
我们新建一个Android项目后应该可以看到很多drawable文件夹,分别对应不同的dpi
- drawable-ldpi (dpi=120, density=0.75)
- drawable-mdpi (dpi=160, density=1)
- drawable-hdpi (dpi=240, density=1.5)
- drawable-xhdpi (dpi=320, density=2)
- drawable-xxhdpi (dpi=480, density=3)
市面上的一些Android教程大多都是教的是为每种dpi都出一套图片资源,这个固然是一种解决办法,但同时也是一种非常笨的方法,为美工或者设计增加了不少的工作量不说,同时也会让你的apk包变的很大。那么有没有什么好的方法既能保证屏幕适配,又可以最小占用设计资源,同时最好又只使用一套dpi的图片资源呢?下面就来讲解下项目中总结出来的这个方法。
首先必须清楚一个自动渲染的概念,Android SDK会自动屏幕尺寸选择对应的资源文件进行渲染,如SDK检测到你手机dpi是160的话会优先到drawable-mdpi文件夹下找对应的图片资源,注意只是优先,假设你手机dpi是160,但是你只在xhpdi文件夹下有对应的图片资源文件,程序一样可以正常运行。所以理论上来说只需要提供一种规格的图片资源就ok了,如果只提供ldpi规格的图片,对于大分辨率的手机如果把图片放大就会不清晰,所以需要提供一套你需要支持的最大dpi的图片,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。
xhdpi成为首选
上面说了只需要提供一套大的dpi的图片就ok了,现在市面手机分辨率最大可达到1080X1920的分辨率,如Nexus5,dpi属于xxhdpi,但是毕竟还没普及,目前市面上最普遍的高端机的分辨率还多集中在720X1080范围,也就是多集中在xhdpi,所以目前来看xhpdi规格的图片成为了首选。当然随着技术规格的提高以后发展,以后可能市场上xxdpi的手机会越来越普遍,但这是后话。
设计资源紧张怎么办?
在现在的App开发中,基本都会有iOS和Android版本,有些公司为了保持App不同版本的体验交互一致,还有些公司的设计资源可能比较紧张,这些情况下iOS和Android版本基本是一个设计师主导,而大多数情况下设计师可能更会以iPhone手机为基础进行设计,包括后期的切图之类的。这个时候身为Android开发人员你是否还要求设计师单独为Android端切一套图片资源呢?这会让你们的设计师崩溃的,下面就来告诉一个项目中总结的更棒的方法。
相信设计师们一般都会用最新的iPhone5(5s和5的尺寸以及分辨率都一样)来做原型设计,而iPhone5的屏幕分辨率为640X1164, 屏幕尺寸为4英寸,根据勾股定理(a^2 + b^2 = c2)6402+1164^2=1764496, 然后再对其开根号可求出屏幕对角线的分辨率为:1328,除以4可得出iphone5的dpi:1328/4≈332 可以看出iPhone5的屏幕的dpi约等于320, 刚好属于xhdpi,所以你可以很自豪的像你们的设计师说不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就ok了。
以下例子参考
Android总结之drawable(hdpi,mdpi,ldpi)文件夹的使用
Android drawable微技巧,你所不知道的drawable的那些细节
出现图二的原因是将放在hdpi下的图片放到了默认的文件夹下
本身图片是同一张图片,由于没有在hdpi文件夹中找到对应图片,系统在默认文件夹下找见了图片资源,但是这时系统会认为改图适用于中等分辨率的屏幕上,如果直接放到高分辨率的手机上不能适配,所以系统会自动的将图片放大,所以虽然是同一张图片,但是现实出来就一个正常效果,一个放大效果。
同理,如果同一张图片,放置在ldpi的文件夹下,在低分辨率的手机上显示正常,但是如果放在hdpi文件夹中,系统认为该图是为高分辨率显示的,要将图片缩小处理,所以显示出来的效果就是图变小了。
所以我们在平时要注意,明明都是一张图片,只是放在不同的文件夹中,显示出来的效果就很不同,原因就是我们对Android还不够了解。