资讯专栏INFORMATION COLUMN

Android屏幕适配方案

XboxYan / 2718人阅读

摘要:下图为图标的各个屏幕密度的对应尺寸屏幕密度图标尺寸解析解析获取屏幕分辨率信息的三种方法第一种第二种第三种屏幕适配出现的原因什么是像素点屏幕分辨率是指在横纵向上的像素点数,单位是,个像素点。

目录介绍

1.屏幕适配定义

2.相关重要的概念

2.1 屏幕尺寸[物理尺寸]

2.2 屏幕分辨率[px]

2.3 屏幕像素密度[dpi]

2.4 dp、dip、dpi、sp、px

2.5 mdpi、hdpi、xdpi、xxdpi

2.6 获取屏幕分辨率[宽高]

3.Android屏幕适配出现的原因

3.1 什么是像素点

3.2 dp与百分比

4.Android适配问题及本质

4.1 尺寸适配

4.2 代码适配

4.3 布局适配

4.4 权重适配

4.5 图片适配

4.6 百分比适配

5.存在问题和困境

5.1 通配符适配困境

5.2 传统dp适配困境

6.常用解决方案

6.1 今日头条适配方案

6.2 鸿洋大神库

6.3 AndroidAutoSize

1.屏幕适配定义

使得某一元素在Android不同尺寸、不同分辨率的手机上具备相同的显示效果

2.相关重要的概念 2.1 屏幕尺寸[物理尺寸]

含义:手机对角线的物理尺寸

单位:英寸(inch),1英寸=2.54cm

Android手机常见的尺寸有5寸、5.5寸、6寸等等

2.2 屏幕分辨率[px]

含义:手机在横向、纵向上的像素点数总和

一般描述成屏幕的"宽x高”=AxB

含义:屏幕在横向方向(宽度)上有A个像素点,在纵向方向 (高)有B个像素点

例子:1080x1920,即宽度方向上有1080个像素点,在高度方向上有1920个像素点

单位:px(pixel),1px=1像素点

Android手机常见的分辨率:720x1280、1080x1920等等

2.3 屏幕像素密度[dpi]

含义:每英寸的像素点数

单位:dpi(dots per ich)

假设设备内每英寸有160个像素,那么该设备的屏幕像素密度=160dpi

屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

dpi计算公式:举个例子:屏幕分辨率为:1920*1080,屏幕尺寸为5吋的话,那么dpi为440

注意:dpi是根据屏幕真实的分辨率和尺寸来计算的,每个设备都可能不一样的

2.4 dp[dip]、dpi、sp、px

dp(dip):px = dp * 密度比,都是Density Independent Pixels的缩写,即密度无关像素

dpi:开方(宽度平方 + 高度平方) / 手机的尺寸;dpi是屏幕像素密度,假如一英寸里面有160个像素,这个屏幕的像素密度就是160dpi

sp: 可以根据文字大小首选项进行放缩,是设置字体大小的御用单位。

px: 像素,px是比较熟悉,前面的分辨率就是用的像素为单位,大多数情况下,比如UI设计、Android原生API都会以px作为统一的计量单位,像素是获取屏幕宽高等。

问题: dp和px如何换算呢?

px = density * dp;
density = dpi / 160;
px = dp * (dpi / 160);
2.5 mdpi、hdpi、xdpi、xxdpi

2.5.1 作用: mdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值。

名称像                     素密度范围
ldpi                      0dpi~120dpi
mdpi                      120dpi~160dpi
hdpi                      120dpi~160dpi
xdpi                      160dpi~240dpi
xxdpi                     240dpi~320dpi
xxxdpi                    480dpi~640dpi

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)
对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。

2.5.2 在进行开发的时候,我们需要把合适大小的图片放在合适的文件夹里面。下面以图标设计为例进行介绍

2.5.3 在设计图标时,对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。

例如,一个启动图标的尺寸为48x48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。

2.5.4 下图为图标的各个屏幕密度的对应尺寸:

屏幕密度                 图标尺寸
mdpi                     48X48px
hdpi                     72X72px
xdpi                     96X96px
xxdpi                    144X144px
xxxdpi                   192X192px
2.6 DisplayMetrics解析

DisplayMetrics解析

获取屏幕分辨率信息的三种方法:

//第一种
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);

//第二种
DisplayMetrics metrics= activity.getResources().getDisplayMetrics();

//第三种
Resources.getSystem().getDisplayMetrics();
3.Android屏幕适配出现的原因 3.1 什么是像素点

屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。

一般以纵向像素横向像素,如19601080。 由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。 屏幕尺寸这么多,为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度(这些概念我会在下面详细讲解)的设备上,那就要在开发的过程中进行处理,至于如何去进行处理,这就是我们今天的主题。

3.2 dp与百分比 (网页前端提供百分比,所以无需适配)

只要记住一点dp是与像素无关的,在实际使用中1dp大约等于1/160inch

那么dp究竟解决了适配上的什么问题?可以看出1dp = 1/160inch;那么它至少能解决一个问题,就是你在布局文件写某个View的宽和高为160dp160dp,这个View在任何分辨率的屏幕中,显示的尺寸大小是大约是一致的(可能不精确),大概是 1 inch 1 inch。

1.呈现效果仍旧会有差异,仅仅是相近而已

当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。

一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。

4.Android屏幕适配常见方法 4.1 适配常见方法

尺寸适配

dimen适配

布局适配

代码适配

图片适配

4.2 尺寸适配 4.2.1 布局文件设置宽高

宽高设置参数:有的时候用dp,有的时候用px,大多数用dp

dp:dp(dip):px = dp * 密度比,与屏幕像素有对应关系,设置成dp后,在不同分辨率的手机上有可能尺寸会不一样

px:像素,比如小分辨率手机上一像素和大分辨率手机上一像素,所显示的图像是不一样的
理解dp和px之间对应的关系,不同分辨率的手机用不同的dp值来适配

4.2.2 密度比

密度比是固定的,可以查询文档Develop—>API Guides—>Best Practices—>Supporting Multiple

mdpi手机:160dpi 是基准线,1px = 1dp * 1,其他手机的密度比 = 自己的dpi/160

代码获取密度比:getResources().getDisplayMetrics().density

ldip:120px = 160dp * 0.75
mdpi:160px = 160dp * 1
hdpi:240px = 160dp * 1.5
xhdpi:360px = 180dp * 2

4.2.3 dimen适配

1.在默认的values中的dimens文件下声明(类似于Strings.xml)

    16dp
    16dp
    160dp



    
    120dip     



    
    220dip     





    
    80dip     

2.在布局文件中引用

3.新建需要适配的values-XXX(比如values-1280x720,注意规范大值在前)

4.在新建values-1280x720中的dimens.xml文件中

* 180dp

5.所有手机适配找对应的默认的dimens

    * 思考:如何计算dpi?如何计算手机密度比?能够用dp适配所有手机吗?
    * dp不能适配所有手机;
    * 举个例子:按钮占屏幕宽度一半,把宽度设置成160dp,120px和160px和240px可以占屏幕一半,但是360px则小于屏幕一半;
    * 如果把宽度设置成180dp,那么360dp可以占屏幕一半,但其他几个又不行。
    * 如果要适配所有手机的控件宽度为屏幕宽度的一半,该怎么做呢?用dimen
4.2 代码适配 4.3 布局适配,有可能在不同的手机布局中,控件排列的位置不一样

1.位置不一样

不同的手机在运行的时候选择不同的布局(布局名称一样,类似于dimens),比如:

2.控件不一样

不能用布局适配了;为什么?

布局能够实现界面效果,但是完成布局后在代码中,由于控件都不一样,所以会找这两套布局的id,还要做判断,根据不同的布局做两套代码(如果页面复杂,给控件设置参数等十分繁琐)

3.适用场景

不同的手机的控件的位置不一样,发生了位置变化才会用到布局适配,实际开发中用的很少

4.4 权重适配 4.5 图片适配

1.图片的查找顺序

注意:一般手机 ldpi

注意:mdpi手机 ldpi

适配主流手机,1920 1080 1080 720 800 * 480,高清图、背景图(全屏展示)准备多套 。小图片 准备一套高分辨率的;比如按钮,图标等

为了是apk瘦身,有些图片不要准备多套,Android分辨率种类太多了;即使适配主流手机,展示比较清楚的背景图(比如:欢迎界面),可以准备多套

2.在小分辨率展示高清图,放到大分辨率会出现什么情况呢?

比如:你针对800480分辨率手机做了背景图图片,正好完全展示;如果把它放到大分辨率1280720上,会对图片进行拉伸,会使像素点变大,可能会看到锯齿或者模糊的东西

5.存在问题和困境 5.1 通配符适配困境 5.2 传统dp适配困境

[摘自头条]一般我们设计图都是以固定的尺寸来设计的。比如以分辨率750px 1334px来设计,以density为3来标注,也就是屏幕其实是350dp 667dp。如果想在所有设备上显示完全一致,其实是不现实的,因为屏幕高宽比不是固定的,各种宽高比层出不穷,宽高比不同,显示完全一致就不可能了。但是通常下,我们只需要以宽或高一个维度去适配,比如我们Feed是上下滑动的,只需要保证在所有设备中宽的维度上显示一致即可,再比如一个不支持上下滑动的页面,那么需要保证在高这个维度上都显示一致,尤其不能存在某些设备上显示不全的情况。同时考虑到现在基本都是以dp为单位去做的适配,如果新的方案不支持dp,那么迁移成本也非常高。

因此,总结下大致需求如下:

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

支持dp和sp单位,控制迁移成本到最小。

6.常用适配框架 6.1 今日头条适配方案 6.1.1 兼容突破口

从dp和px的转换公式 :px = dp * density

可以看出,如果设计图宽为360dp,想要保证在所有设备计算得出的px值都正好是屏幕宽度的话,我们只能修改 density 的值。

//在xml中使用何种尺寸单位(dp、sp、pt、in、mm),最后在绘制时都会给我们转成px!
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;
}
6.1.2 头条适配方案核心代码
public static void setCustomDensity(Activity activity, Application application) {
    DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
    if (sNoncompatDensity == 0) {
        // 系统的Density
        sNoncompatDensity = displayMetrics.density;
        // 系统的ScaledDensity
        sNoncompatScaledDensity = displayMetrics.scaledDensity;
        // 监听在系统设置中切换字体
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                if (newConfig != null && newConfig.fontScale > 0) {
                    sNoncompatScaledDensity=application.getResources().getDisplayMetrics().scaledDensity;
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }
    // 公司UI尺寸是750px-1334px,此处以375dp的设计图作为例子
    float targetDensity=displayMetrics.widthPixels/375;
    float targetScaledDensity=targetDensity*(sNoncompatScaledDensity/sNoncompatDensity);
    int targetDensityDpi= (int) (160 * targetDensity);
    displayMetrics.density = targetDensity;
    displayMetrics.scaledDensity = targetScaledDensity;
    displayMetrics.densityDpi = targetDensityDpi;

    DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
    activityDisplayMetrics.density = targetDensity;
    activityDisplayMetrics.scaledDensity = targetScaledDensity;
    activityDisplayMetrics.densityDpi = targetDensityDpi;
}
6.1.3 头条适配方案注意事项

宽度适配就已经完成啦,只需要在Activity中调用就行了,必须在setContentView()之前!

如果需要适配高度,头条指出只要按照同样的方法做高度适配就可以了!

实现思路:假设设计图宽度是360dp,以宽维度来适配,那么适配后的 density = 设备真实宽(单位px) / 360,接下来只需要把我们计算好的 density 在系统中修改下即可

遇到的问题:

1.如果某个页面不想适配该方案,该如何处理

2.滚动页面以宽为维度适配,而某些页面则是以高为维度适配,这种情况怎么办?

3.针对第三方库有何更好的方案,比如支付宝支付弹窗,或者第三方客服聊天页面如何处理适配

6.1.4 头条适配工具类,暂时只是用作测试项目

关于该工具类,已经用于测试项目中,逐步完善,项目可以参考:https://github.com/yangchong2...

public class ScreenDensityUtils {


    /*
     * 1.先在application中使用setup()方法初始化一下
     * 2.手动在Activity中调用match()方法做适配,必须在setContentView()之前
     * 3.建议使用dp做宽度适配,大多数时候宽度适配才是主流需要
     * 4.个人觉得在写布局的时候,可以多用dp,如果是使用px,建议转化成dp
     * 5.入侵性很低,不需要改动原来的代码
     */


    /**
     * 屏幕适配的基准
     */
    private static final int MATCH_BASE_WIDTH = 0;
    private static final int MATCH_BASE_HEIGHT = 1;
    /**
     * 适配单位
     */
    private static final int MATCH_UNIT_DP = 0;
    private static final int MATCH_UNIT_PT = 1;

    // 适配信息
    private static MatchInfo sMatchInfo;
    // Activity 的生命周期监测
    private static Application.ActivityLifecycleCallbacks mActivityLifecycleCallback;

    private ScreenDensityUtils() {
        throw new UnsupportedOperationException("u can"t instantiate me...");
    }

    /**
     * 初始化
     * @param application                   需要在application中初始化
     */
    public static void setup(@NonNull final Application application) {

        /*
        //获取屏幕分辨率信息的三种方法
        //第一种
        DisplayMetrics metrics = new DisplayMetrics();
        Display display = activity.getWindowManager().getDefaultDisplay();
        display.getMetrics(metrics);
        //第二种
        DisplayMetrics metrics= activity.getResources().getDisplayMetrics();
        //第三种
        Resources.getSystem().getDisplayMetrics();
        */

        //注意这个是获取系统的displayMetrics
        final DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
        if (sMatchInfo == null) {
            // 记录系统的原始值
            sMatchInfo = new MatchInfo();
            sMatchInfo.setScreenWidth(displayMetrics.widthPixels);
            sMatchInfo.setScreenHeight(displayMetrics.heightPixels);
            sMatchInfo.setAppDensity(displayMetrics.density);
            sMatchInfo.setAppDensityDpi(displayMetrics.densityDpi);
            sMatchInfo.setAppScaledDensity(displayMetrics.scaledDensity);
            sMatchInfo.setAppXdpi(displayMetrics.xdpi);
        }
        // 添加字体变化的监听
        // 调用 Application#registerComponentCallbacks 注册下 onConfigurationChanged 监听即可。
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                // 字体改变后,将 appScaledDensity 重新赋值
                if (newConfig != null && newConfig.fontScale > 0) {
                    float scaledDensity = displayMetrics.scaledDensity;
                    sMatchInfo.setAppScaledDensity(scaledDensity);
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }

    /**
     * 在 application 中全局激活适配(也可多带带使用 match() 方法在指定页面中配置适配)
     */
    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static void register(@NonNull final Application application, final float designSize, final int matchBase, final int matchUnit) {
        if (mActivityLifecycleCallback == null) {
            mActivityLifecycleCallback = new Application.ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    if (activity != null) {
                        match(activity, designSize, matchBase, matchUnit);
                    }
                }

                @Override
                public void onActivityStarted(Activity activity) {

                }

                @Override
                public void onActivityResumed(Activity activity) {

                }

                @Override
                public void onActivityPaused(Activity activity) {

                }

                @Override
                public void onActivityStopped(Activity activity) {

                }

                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

                }

                @Override
                public void onActivityDestroyed(Activity activity) {

                }
            };
            application.registerActivityLifecycleCallbacks(mActivityLifecycleCallback);
        }
    }

    /**
     * 全局取消所有的适配
     */
    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static void unregister(@NonNull final Application application, @NonNull int... matchUnit) {
        if (mActivityLifecycleCallback != null) {
            application.unregisterActivityLifecycleCallbacks(mActivityLifecycleCallback);
            mActivityLifecycleCallback = null;
        }
        for (int unit : matchUnit) {
            cancelMatch(application, unit);
        }
    }


    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     *
     * @param context                               上下文
     * @param designSize                            设计图的尺寸
     */
    public static void match(@NonNull final Context context, final float designSize) {
        match(context, designSize, MATCH_BASE_WIDTH, MATCH_UNIT_DP);
    }


    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     *
     * @param context                               上下文
     * @param designSize                            设计图的尺寸
     * @param matchBase                             适配基准
     */
    public static void match(@NonNull final Context context, final float designSize, int matchBase) {
        match(context, designSize, matchBase, MATCH_UNIT_DP);
    }

    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     *
     * @param context                               上下文
     * @param designSize                            设计图的尺寸
     * @param matchBase                             适配基准
     * @param matchUnit                             使用的适配单位
     */
    private static void match(@NonNull final Context context, final float designSize, int matchBase, int matchUnit) {
        if (designSize == 0) {
            throw new UnsupportedOperationException("The designSize cannot be equal to 0");
        }
        if (matchUnit == MATCH_UNIT_DP) {
            matchByDP(context, designSize, matchBase);
        } else if (matchUnit == MATCH_UNIT_PT) {
            matchByPT(context, designSize, matchBase);
        }
    }

    /**
     * 重置适配信息,取消适配
     */
    public static void cancelMatch(@NonNull final Context context) {
        cancelMatch(context, MATCH_UNIT_DP);
        cancelMatch(context, MATCH_UNIT_PT);
    }

    /**
     * 重置适配信息,取消适配
     *
     * @param context                       上下文
     * @param matchUnit                     需要取消适配的单位
     */
    private static void cancelMatch(@NonNull final Context context, int matchUnit) {
        if (sMatchInfo != null) {
            final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
            if (matchUnit == MATCH_UNIT_DP) {
                if (displayMetrics.density != sMatchInfo.getAppDensity()) {
                    displayMetrics.density = sMatchInfo.getAppDensity();
                }
                if (displayMetrics.densityDpi != sMatchInfo.getAppDensityDpi()) {
                    displayMetrics.densityDpi = (int) sMatchInfo.getAppDensityDpi();
                }
                if (displayMetrics.scaledDensity != sMatchInfo.getAppScaledDensity()) {
                    displayMetrics.scaledDensity = sMatchInfo.getAppScaledDensity();
                }
            } else if (matchUnit == MATCH_UNIT_PT) {
                if (displayMetrics.xdpi != sMatchInfo.getAppXdpi()) {
                    displayMetrics.xdpi = sMatchInfo.getAppXdpi();
                }
            }
        }
    }


    public static MatchInfo getMatchInfo() {
        return sMatchInfo;
    }


    /**
     * 使用 dp 作为适配单位(适合在新项目中使用,在老项目中使用会对原来既有的 dp 值产生影响)
     * 
*
    * dp 与 px 之间的换算: *
  • px = density * dp
  • *
  • density = dpi / 160
  • *
  • px = dp * (dpi / 160)
  • *
* * @param context 上下文 * @param designSize 设计图的宽/高(单位: dp) * @param base 适配基准 */ private static void matchByDP(@NonNull final Context context, final float designSize, int base) { final float targetDensity; if (base == MATCH_BASE_WIDTH) { targetDensity = sMatchInfo.getScreenWidth() * 1f / designSize; } else if (base == MATCH_BASE_HEIGHT) { targetDensity = sMatchInfo.getScreenHeight() * 1f / designSize; } else { targetDensity = sMatchInfo.getScreenWidth() * 1f / designSize; } final int targetDensityDpi = (int) (targetDensity * 160); final float targetScaledDensity = targetDensity * (sMatchInfo.getAppScaledDensity() / sMatchInfo.getAppDensity()); final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); displayMetrics.density = targetDensity; displayMetrics.densityDpi = targetDensityDpi; displayMetrics.scaledDensity = targetScaledDensity; } /** * 使用 pt 作为适配单位(因为 pt 比较冷门,新老项目皆适合使用;也可作为 dp 适配的补充, * 在需要同时适配宽度和高度时,使用 pt 来适配 dp 未适配的宽度或高度) *
*

pt 转 px 算法: pt * metrics.xdpi * (1.0f/72)

* * @param context 上下文 * @param designSize 设计图的宽/高(单位: pt) * @param base 适配基准 */ private static void matchByPT(@NonNull final Context context, final float designSize, int base) { final float targetXdpi; if (base == MATCH_BASE_WIDTH) { targetXdpi = sMatchInfo.getScreenWidth() * 72f / designSize; } else if (base == MATCH_BASE_HEIGHT) { targetXdpi = sMatchInfo.getScreenHeight() * 72f / designSize; } else { targetXdpi = sMatchInfo.getScreenWidth() * 72f / designSize; } final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); displayMetrics.xdpi = targetXdpi; } /** * 适配信息 */ private static class MatchInfo { private int screenWidth; private int screenHeight; private float appDensity; private float appDensityDpi; private float appScaledDensity; private float appXdpi; int getScreenWidth() { return screenWidth; } void setScreenWidth(int screenWidth) { this.screenWidth = screenWidth; } int getScreenHeight() { return screenHeight; } void setScreenHeight(int screenHeight) { this.screenHeight = screenHeight; } float getAppDensity() { return appDensity; } void setAppDensity(float appDensity) { this.appDensity = appDensity; } float getAppDensityDpi() { return appDensityDpi; } void setAppDensityDpi(float appDensityDpi) { this.appDensityDpi = appDensityDpi; } float getAppScaledDensity() { return appScaledDensity; } void setAppScaledDensity(float appScaledDensity) { this.appScaledDensity = appScaledDensity; } float getAppXdpi() { return appXdpi; } void setAppXdpi(float appXdpi) { this.appXdpi = appXdpi; } } }
6.2 鸿洋大AutoLayout框架

我记得上上一个公司的项目投资界就是用的这个屏幕适配库……哈哈

该库的想法非常好:对照设计图,使用px编写布局,不影响预览;绘制阶段将对应设计图的px数值计算转换为当前屏幕下适配的大小;为简化接入,inflate时自动将各Layout转换为对应的AutoLayout,从而不需要在所有的xml中更改。但是同时该库也存在以下等问题:

扩展性较差。对于每一种ViewGroup都要对应编写对应的AutoLayout进行扩展,对于各View的每个需要适配的属性都要编写代码进行适配扩展;

在onMeasure阶段进行数值计算。消耗性能,并且这对于非LayoutParams中的属性存在较多不合理之处。比如在onMeasure时对TextView的textSize进行换算并setTextSize,那么玩家在代码中动态设置的textSize都会失效,因为在每次onMesasure时都会重新被AutoLayout重新设置覆盖。

issue较多并且作者已不再维护。

个人觉得AutoLayout的设计思想非常优秀,但是将LayoutParams与属性作为切入口在mesure过程中进行转换计算的方案存在效率与扩展性等方面的问题。那么Android计算长度的收口在哪里,能不能在Android计算长度时进行换算呢?如果能在Android计算长度时进行换算,那么就不需要一系列多余的计算以及适配,一切问题就都迎刃而解了

6.3 AndroidAutoSize

已经用于现在正式库,代码量多,且注释也比较项目,作者更新很频繁,极力维护并解决bug,非常不错!

关于其他内容介绍 01.关于博客汇总链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.其他汇总

02.关于我的博客

我的个人站点:www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

简书:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo...

开源中国:https://my.oschina.net/zbj161...

泡在网上的日子:http://www.jcodecraeer.com/me...

邮箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault头条:https://segmentfault.com/u/xi...

03.参考博客

一种极低成本的Android屏幕适配方式:https://mp.weixin.qq.com/s/d9...

Android 屏幕适配从未如斯简单:https://juejin.im/post/5b6250...

今日头条适配方案:https://www.jianshu.com/p/55e...

Android 目前最稳定和高效的UI适配方案:https://www.jianshu.com/p/a4b...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77124.html

相关文章

  • Android屏幕适配方案分析

    摘要:下面来看看常见的三种比较成熟的屏幕适配方案,并分析这几种方案的优劣。屏幕适配方案宽高限定符适配设定一个基准的分辨率,也就是设计图对应的分辨率,其他分辨率都根据这个基准分辨率来计算,在不同的尺寸文件夹内部,根据该尺寸编写对应的文件。 为什么要屏幕适配 Android开发过程中我们常用的尺寸单位有px、dp,还有一种sp一般是用于字体的大小。但是由于px是像素单位,比如我们通常说的手机分辨...

    Achilles 评论0 收藏0
  • Android屏幕适配方案

    摘要:下图为图标的各个屏幕密度的对应尺寸屏幕密度图标尺寸解析解析获取屏幕分辨率信息的三种方法第一种第二种第三种屏幕适配出现的原因什么是像素点屏幕分辨率是指在横纵向上的像素点数,单位是,个像素点。 目录介绍 1.屏幕适配定义 2.相关重要的概念 2.1 屏幕尺寸[物理尺寸] 2.2 屏幕分辨率[px] 2.3 屏幕像素密度[dpi] 2.4 dp、dip、dpi、sp、px 2.5 md...

    Sourcelink 评论0 收藏0
  • 屏幕适配全方位解析

    摘要:需要注意的是,这种通过限定符分辨屏幕尺寸的方法,适用于之前。这种最小宽度限定符适用于之后,所以如果要适配全部的版本,就要使用限定符和文件同时存在于项目目录下。 1.屏幕适配概念 而随着支持Android系统的设备(手机、平板、电视、手表)的增多,设备碎片化、品牌碎片化、系统碎片化、传感器碎片化和屏幕碎片化的程度也在不断地加深。而我们今天要探讨的,则是对我们开发影响比较大的——屏幕的碎片...

    mochixuan 评论0 收藏0

发表评论

0条评论

XboxYan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<