Android app 适配

有过android手机或者盒子(TV)开发经历的工程师都知道,app的适配是很头疼的工作。最近也在做相关工作,为此把自己学习和实战的经验分享在这儿,希望对有需要的同学有所帮助。

首先分享几篇适配相关的android官方文档:

API Guides-->Best Practices-->Supporting Multiple Screens

http://developer.android.com/guide/practices/screens_support.html

API Guides-->App Resources-->Providing Resources

http://developer.android.com/guide/topics/resources/providing-resources.html

Training-->Best Practices for User Interface -->Designing for Multiple Screens

http://developer.android.com/training/multiscreen/index.html

9图 API Guides-->Animation and Graphics-->Canvas and Drawables

http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch

上面几篇文章都是讲如何适配的,笔者也是初略的看了一遍,需要多看几遍才能很好的理解和掌握。

有几点笔者需要说明一下,也是自己不理解的地方。

(1)按照android官方定义,dpi也就是屏幕密度是屏幕每英寸上的像素点。但是对于,盒子设备来说,根本就没有屏幕,dpi如何来?可是我们从系统中是能读到density的。这就是笔者不理解的一个地方。

下面以一个实际的例子来说明适配,以drawable为例来说明

项目中如下几个drawable文件夹

drawable

drawable-ldpi

drawable-sw1000dp-mdpi

drawable-sw600dp-hdpi

drawable-xhdpi

有这个三星S4 GT-I9500型号的手机,参数如下:

screenWidth = 1080 screenHeight = 1920 densityDpi = 480 scale = 3.0 fontScale = 3.0 xdpi = 442.451 ydpi = 443.345 screenInches = 4.971247911145661

在看下面分析过程前,请先看一下第二篇文章中的How Android Finds the Best-matching Resource部分。

dpi为480,属于xxhpi。

1080*1920px换算成dp是360*640dp。按照下图中的第一步,drawable-sw1000dp-mdpi和drawable-sw600dp-hdpi被排除。注意dpi是不会用于排除条件的,文章中有强调这一点。

Exception: If the qualifier in question is screen pixel density, Android selects the option that most closely matches the device screen density. In general, Android prefers scaling down a larger original image to scaling up a smaller original image. See Supporting Multiple Screens.

接下来就是根据dpi的选择了,请看上面的描述。设备的density是xxhpi,选择最近的dpi就是xhdpi,所以系统会从drawable-xhdpi文件夹下读取资源。需要注意的,xhdpi文件夹下的图片会scaling up到xxhpi。

为了验证我们的想法,我们可以先把drawable-xhdpi文件夹删了,安装到S4上试试,app直接就崩溃了,因为找不到资源文件。

经过试验有种奇怪的现象,不知道为什么但很重要,需要说明一下。

比如我们有如下的文件夹

drawable

drawable-ldpi

drawable-mdpi

drawable-sw1000dp-mdpi

drawable-sw600dp-hdpi

drawable-xhdpi

我们有个杰科的盒子,参数如下:

screenWidth = 1280 screenHeight = 672 densityDpi = 160 scale = 1.0 fontScale = 1.0 xdpi = 160.15764 ydpi = 160.42105 screenInches = 9.0233918316934

1280*672px换算成dp是1280*672dp。根据下图规则步骤1,我们排除drawable-sw1000dp-mdpi文件夹,目前保留文件夹如下:

drawable

drawable-ldpi

drawable-mdpi

drawable-sw600dp-hdpi

drawable-xhdpi

执行步骤2、3,我们需要排除drawable、drawable-ldpi、drawable-mdpi、drawable-xhdpi文件夹,因为这些文件夹不包含size的qualifier。

最终只保留drawable-sw600dp-hdpi这个文件夹,刚好672dp满足sw600dp,hdpi到mdpi也没有问题。完美,到这是问题好像一切都解决了。

But,有中情况,假如有个资源文件在drawable-sw600dp-hdpi文件夹下没有,在drawable-mdpi文件夹下有,你认为此时应用会崩溃吗?

按照上面的分析,答案是肯定的,应用肯定会崩溃,因为找不到资源。

但是,实际不是这样的,应用不会崩溃,而是从drawable-mdpi取到资源。这就是我理解的地方。

我是这样的理解的,可能对size这个qualifer来说(也就是sw***),明显不满足的可以排除,比如:drawable-sw1000dp-mdpi。对于剩下的都可以保留,只不过drawable-sw600dp-hdpi是最满意的,如果drawable-sw600dp-hdpi中没有想要的资源,可以从其他文件夹中取,只有根据相应的dpi scale就行。

Android app 适配_第1张图片


values下面的dimens选择需要说明一下:

dimens中值的单位都是sp或者dp。从dimens读出来来的值*(设备density/160)=真正的值px。

以S4为例,从values-xhdpi文件夹下读取的值*(480/160)。这个结果肯定是不对的。因此,我们需要建一个values-xxhdpi的文件夹,里面的dimens要重新按比例换算一遍。这样才对。


再说一下图片的scale问题

有如下的布局文件:




    

    

focus_shadow和focus_shadow_new都是相同的9图,只是名字不一样而已。

我们有个杰科的盒子,参数如下:

screenWidth = 1280 screenHeight = 672 densityDpi = 160 scale = 1.0 fontScale = 1.0 xdpi = 160.15764 ydpi = 160.42105 screenInches = 9.0233918316934

在此设备上运行测试。

目录结构如下:



focus_shadow放到drawabl-nodpi文件夹下。

focus_shadow_new放到drawable-sw600dp-hdpi文件夹下。

运行效果如下:

Android app 适配_第2张图片

focus_shadow放到drawabl-nodpi文件夹下。

focus_shadow_new放到drawable-mdpi文件夹下。

注意:这种情况就是上面我们描述的特殊情况。

Android app 适配_第3张图片

focus_shadow放到drawabl-nodpi文件夹下。

focus_shadow_new放到drawable-sw1000dp-mdpi文件夹下。

app崩溃

focus_shadow放到drawabl-nodpi文件夹下。

focus_shadow_new放到drawable-xxhdpi文件夹下。

Android app 适配_第4张图片


这几种情况为什么会这样,上面都已经描述过了,大家自己分析吧。

有什么问题,欢迎留言交流。



你可能感兴趣的:(Android,Android实战)