1. 引论

众所周知,Android机型尺寸各种各样,于是屏幕适配就成了Android开发中很重要的一环。Android屏幕适配可能一些开发者都会遇到这样的问题,、

今天就来分享下屏幕适配,其实Android屏幕适配也可以很简单。

参考:1. http://www.cnblogs.com/yaozhongxiao/archive/2014/07/14/3842908.html

         2. http://www.cnblogs.com/ycxyyzw/p/3889939.html

2. Android下尺寸的基本单位

① px 像素

是英文单词pixel的缩写,意为像素,屏幕上的点。我们通常所说的分辨率如480X800就是指的像素。

px是个绝对单位,在不同尺寸的手机设备下,像素固定显示效果就是一样的!

在设计领域中,像素是用来计算数码影像的最小单位。计算机中显示的图像并非连续的线条组成,而是由许多肉眼看不见的小点组成。

如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小点所组成,这些小点就是构成影像的最小单位“像素”。由于是最小的独立显示单位,px均为整数,不会出现0.5px的情况。

② in 英寸

表示英寸,是屏幕的物理尺寸。每英寸等于2.54厘米。例如我们经常说的手机屏幕大小有,5(英)寸、4(英)寸就是指这个单位。这些尺寸是屏幕的对角线长度。如果手机的屏幕是4英寸,表示手机的屏幕

(可视区域)对角线长度是4 X 2.54 = 10.16厘米。

应该明白我们常说的屏幕是4寸指的是:屏幕对角线是4寸

③ dpi  每英寸包含像素个数

dpi是Dots Per Inch的缩写, 每英寸点数,即每英寸包含像素个数。比如320X480分辨率的手机,宽2英寸,高3英寸, 每英寸包含的像素点的数量为320/2=160dpi(横向)或480/3=160dpi(纵向),160

就是这部手机的dpi,横向和纵向的这个值都是相同的,原因是大部分手机屏幕使用正方形的像素点。常见取值 120,160,240。一般称作像素密度,简称密度

④ density 屏幕密度

屏幕密度,density和dpi的关系为 density = dpi/160,为了与dpi称呼区别一般叫做屏幕密度,或者直接教density

⑤ dp 设备独立像素

也即dip,设备独立像素,device independent pixels的缩写,Android特有的单位,常见取值 1.5 , 1.0 。和标准dpi的比例(160px/inc)即在屏幕密度dpi = 160屏幕上,1dp = 1px。

⑥ sp 放大像素

与sp类似(设备独立),主要用于字体显示,和dp的区别是它可以根据用户的字体大小偏好来缩放。

注意点1: pixs = dips * (dpi/160) 也就是说相同的dip(dp)在不同的屏幕密度下会代表不同个像素点

              如: 定义一个矩形10 x 10dip.在分辨率为160dpi的屏上,比如G1,正好是10 x 10像素。而在240 dpi的屏,则是15 x 15像素

注意点2:根据google的推荐,统一使用dip,字体则使用sp,这样更好看

3. 各单位的转换

① 计算dpi与屏幕密度density

dpi = (px/inch) /(160 px/inch)

比如一个机器,屏幕4寸,分辨率480X800,他的dpi能算么。

因为不知道边长,肯定不能分开算,4 寸是对角线长度,那直接用勾股定理算对角线像素,除以4,算出来大概是 dpi = 233 像素/英寸。

那么density就是 (233 px/inch)/(160 px/inch)=1.46 左右

顺带说下,android默认的只有3个dpi,low、medium和high,对应 120、160、240,如果没有特别设置,所有的dpi都会被算成这3个,其中的default就是160。

② dp与px 设备独立像素与像素的转换

我们写布局的时候,肯定还是要知道1个dp到底有多少px的。

换算公式如下: dp = (DPI/(160像素/英寸))px = density px ,也就是 屏幕密度×像素 = 独立设备像素

假设dpi是240 像素/英寸 , 那么density就是1.5,那么就是 1dp=1.5px 

 ③ 为什么我们在布局时尽量要用dip,而不是px?

http://www.cnblogs.com/yaozhongxiao/archive/2014/07/14/3842908.html

4. android Drawble目录

  • 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)

可以看到drawable文件夹,分别对应不同的dpi

古老方案:市面上的一些Android教程大多都是教的是为每种dpi都出一套图片资源,这个固然是一种解决办法,但同时也是一种非常笨的方法,为美工或者设计增加了不少的工作量不说,同时也会让你的apk包

变的很大。那么有没有什么好的方法既能保证屏幕适配,又可以最小占用设计资源,同时最好又只使用一套dpi的图片资源呢?

 

首先必须清楚一个自动渲染的概念,Android SDK会自动屏幕尺寸选择对应的资源文件进行渲染,如SDK检测到你手机dpi是160的话会优先到drawable-mdpi文件夹下找对应的图片资源,注意只是优先,假设

你手机dpi是160,但是你只在xhpdi文件夹下有对应的图片资源文件,程序一样可以正常运行。所以理论上来说只需要提供一种规格的图片资源就ok了,如果只提供ldpi规格的图片,对于大分辨率的手机如果把

图片放大就会不清晰,所以需要提供一套你需要支持的最大dpi的图片,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。

 

② 重点需要明白: 

 

  <View 
           android:layout_height="1dip"
           android:layout_width="100dip"/>

该View在密度为160dip的屏幕上显示的长度为100px(像素)长,而在320dip的屏幕上它的长度将为200px。

在图片处于drawable文件夹内时,也需要做这种转换。

假如在drawable-mdpi的文件夹内有一张22*44的图片,通过程序将其读入系统中时,假设屏幕密度为320dip,那它在内存中的大小将是44*88。

总结:   本机系统的DPI > 图片所在文件夹的DPI  图片将会被放大

          本机系统的DPI < 图片所在文件夹的DPI  图片将会被缩小

目前主流做法是将图片放置在drawable-hdpi文件夹内,该文件夹对应的density是240dip,但其实现在的手机一般都是320dip甚至480dip了,

所以放置在hdpi文件夹内的图片在显示时都是已经自动拉伸过了。

③ 当图片是从其他地方而来,如直接读取sd卡或assert文件夹内的图片或网络下载来时的情况

首先获取的不是drawbale对象而是个bitmap对象,该bitmap对象的width和height对应的是图片的真实像素大小。

而将bitmap对象转换为drawable时,除非我们手动设置了目标density,否则不进行缩放。

BitmapDrawable bmpDrawable = new BitmapDrawable(bitmap);

使用这个构造函数,默认的density是160,该构造函数已经被摒弃了,推荐使用下一个

BitmapDrawable bmpDrawable = new BitmapDrawable(getResources(),bitmap);

该构造函数会通过getResources获取到手机的density,将其设置为默认的density。

getResources().getDisplayMetrics().densityDpi

若我们需要进行缩放,可以通过下述方法设置目标density。

bmpDrawable.setTargetDensity(160)

在320dip长度的屏幕上,该bmpDrawable将会缩小为一半。

        

5. android下尺寸描述工具类

① 得到屏幕宽和高

 public static int getWidth(Context context){ 
        WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 
        DisplayMetrics outMetrics = new DisplayMetrics(); 
        wm.getDefaultDisplay().getMetrics(outMetrics); 
        return outMetrics.widthPixels; 
    

DisplayMetrics的toString()方法如下:

复制代码
    @Override
    public String toString() {
        return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
            ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
            ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
    }
复制代码

② dp与dx的转化

**
* 根据手机的分辨率从 dip 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}

/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp==dip
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}