美文网首页
AndroidUI适配全解析---亲自动手一一测试

AndroidUI适配全解析---亲自动手一一测试

作者: 善笃有余劫 | 来源:发表于2018-07-02 12:00 被阅读29次

前言

android的碎片化带来的适配问题一直是大家的心腹大患。虽然官方提供了dp/sp来作为适配单位,但是并没有完全解决问题。

不管是民间还是官方都提供了其他的适配方案,接下来本人给大家测试所有的主流适配方案,并提供测试截图。从使用成本到效果分析供选择适配方式。

适配方案一览

  1. 官方适配方案dp和sp单位

  2. 鸿洋适配方案AndroidAutoLayout

3.资源限定符方案

  1. smallestWidth适配方案
  1. 今日头条团队的适配方案

测试使用的标注图

一张使用dp/sp标注

通知消息.png

一张使用px标注

通知消息.png

五种尺寸的模拟器

TIM截图20180630155334.png

直接使用官方的dp/sp

xml文件就不贴了,直接来看效果吧

五种尺寸ldpi/mdpi/hdpi/xhdpi/xxhdpi

使用dpsp效果图.png

分析:可以明显看到在低dpi情况下,显示的效果不是预期的效果。所以直接使用dp/sp是无法适配成功的。

AndroidAutoLayout

关于这个方案,我看了相关介绍说明之后就直接放弃了。

1.这个方案的使用成本非常高,需要在view的onMeasure里面变化和测量。
2.框架已停止维护,如果需要自己的viewgroup,需要继承自定义,而且支持的属性有限
3.入侵性极强,几乎需要改掉所有的控件

资源限定符

右键res文件夹新建资源文件夹,可以看到左边的条件。
这些条件就是所谓的限定符

TIM截图20180630161812.png

包括 屏幕的宽高,屏幕的密度,屏幕的方向,屏幕的大小等限定条件。如果设备满足当前的条件,就能选择对应的资源文件。

我们采用宽高来限定资源的适配,同时将设计稿和宽高对应起来。

通常设计稿矿都1080px x1920 px的,对应到各种不同的尺寸的手机上,写出对应的dimens文件

对于xxh 1920x1080 的手机就是1px
对于xh的手机 就是 0.66px
对于h的手机就是0.5px

将设计稿的px数据盖上去就可以了啊,也不用给美工解释什么sp/dp

听起来这种方案确实能够解决适配问题,但是关键问题来了,你需要列举到所有的手机的宽高才能解决问题。

一旦没能找到对应的限定符,将使用默认的资源文件。界面必将变形。如果你默认的dimens没有对应的数组将直接异常崩溃

测试: 编写对应的资源尺寸文件

image.png

先来一个没有的尺寸 240x400

image.png

可以看到由于使用了默认的尺寸,拉伸的很夸张

来一个1920x1080的尺寸

image.png

完美显示了

可以完成不同屏幕大小的适配,但是本方案需要计算所有的宽高不同的屏幕数据,而且及其容易因为没有对应的尺寸而被异常拉伸。

限定符用的更多的地方其实是横竖屏切换的布局变化以及平板和手机之间的适配问题。

smallestWidth适配方案

smallestWidth 也就是最小宽度限定

指的是Android会识别屏幕可用高度和宽度的最小尺寸的dp值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。

怎么计算这个smallestWidth值呢:

smallestWidth=屏幕宽度/(dpi/160)
也就计算出对应的屏幕dp值

比如最常见的xxh

smallestWidth=1080/(480/160)=360

所以我们新建一个文件夹

image.png

然后计算这个宽度下对应的px与dp的换算关系

<dimen name="base_dpi">360dp</dimen>
<dimen name="qb_px_0">0.00dp</dimen>
...
...
<dimen name="qb_px_1079">359.67dp</dimen>
<dimen name="qb_px_1080">360.00dp</dimen>

我们穷举0-1080px对应的dp值,方便使用

为什么叫最小宽度呢,因为如果没有找到对应的宽度,就会下来一点点,即找到最小最接近这个值的宽度。

所以相对的我们可以搞多个最小宽度

image.png

当然这些东西写起来麻烦,可以使用一个工具
来自参考文章的sw生成工具

注意修改的几个参数:
设计稿宽度:private static final int DESIGN_WIDTH = 1080;
添加适配的宽度:

//适配Android 3.2以上   大部分手机的sw值集中在  300-460之间
    DP_sw__300(300),  // values-sw300
    DP_sw__310(310),
    DP_sw__320(320),
    DP_sw__330(330),
    DP_sw__340(340),
    DP_sw__350(350),
    DP_sw__360(360),
    DP_sw__370(370),
    DP_sw__380(380),
    DP_sw__390(390),
    DP_sw__400(400);

生成的最大px值
private static final int MAX_SIZE = 1080;

最后来测试一下这个方案把,看效果图

未标题-1.png

效果还是不错的

方案比较可靠,使用起来也很简单只需要输入正确的px值就行,无需解释dp/sp。生成对应的文件也很方便。

今日头条团队的适配方案

关于今日头条的方案,大家可以点进去看。大概的原理和上面的sw方案有点类似。

原理就是

支持以宽或者高一个维度去适配,保持该维度上和设计图一致;

通常我们使用宽度来维持这个适配。比如1080x1920的设计搞对应360dp的宽度。
然后通过系统参数计算出设备实际的宽度,相除得到一个缩放比例。
density = 设备真实宽(单位px) / 360

只需要维持这个比例就可以保证适配。

贴一下转载的代码:

 private static float sNoncompatDensity;
    private static float sNoncompatScaleDensity;
    public static void setCustomDensity(Activity activity , final Application application){
        final DisplayMetrics appDisplayMertics=application.getResources().getDisplayMetrics();
        if(sNoncompatDensity==0){
            sNoncompatDensity=appDisplayMertics.density;
            sNoncompatScaleDensity=appDisplayMertics.scaledDensity;
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if(newConfig!=null&&newConfig.fontScale>0){
                        sNoncompatScaleDensity=application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }

        //以 360 为 维度 适配 注意转为float 不要丢失精度
        float targetDensity = (float) appDisplayMertics.widthPixels / 360;
        float targetScaleDensity = targetDensity * (sNoncompatScaleDensity / sNoncompatDensity);
        int targetDensityDpi = (int) (160 * targetDensity);
        appDisplayMertics.density = targetDensity;
        appDisplayMertics.scaledDensity = targetScaleDensity;
        appDisplayMertics.densityDpi = targetDensityDpi;

        final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaleDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;

    }

使用:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ScreenAdaptUtils.setCustomDensity(this,getApplication());
        setContentView(R.layout.activity_toutiao_test);
    }

值得注意的是需要加上float,这个在原文中没有,在公众号的留言里有勘误。

//以 360 为 维度 适配 注意转为float 不要丢失精度
        float targetDensity = (float) appDisplayMertics.widthPixels / 360;

测试截图:

未标题-1.png

显示完美,接入方便成本低。

总结

当然方案应该还有,但是使用的人少没有纳入。
5个方案来说,4,5应该可以纳入考虑。

sw方案生成dimens文件夹简单可重复使用,而且不用给美工妹子解释dp/sp,使用px即可。

今日头条方案接入简单,但是我测试的发现这个函数会修改整个项目的值。所以老项目应该是不能乱动的。

文章待更新,如果还有更好的方案会继续测试。

本文相关链接和文章

相关文章

网友评论

      本文标题:AndroidUI适配全解析---亲自动手一一测试

      本文链接:https://www.haomeiwen.com/subject/qkzoyftx.html