一种极低成本的Android屏幕适配方式

前言:前段时间在一个技术网站中看到一篇文章:一种极低成本的Android屏幕适配方式,原文地址:https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA,拜读后感觉方法很独特,直接从源码着手解决问题,动手实践了一下,出现了一些问题,解决后感觉适配效果很好,于是推荐给小伙伴们使用,但是有人说看不懂,不知道怎么使用,所以决定写一点使用心得分享给大家,注:本文只教大家如何使用,如想了解实现原理请移步原文地址

 

首先来看原文最终方案代码:

 

你没有看错,就是这么简单,就这些代码就能实现适配???,是不是感觉贼不靠谱的样子,好吧,其实我也不信,于是照着这张图片手打下来(ps:真是纯手打的,因为他的原文终极解决方案代码就是一张图片...放心我不会也这么给你们一张图片的,待会儿放源码),写在BaseActivity中,

在这里要注意了:appDisplayMetrice.widthPixels/360,这个360是你设计图的宽度的dp大小,一定要根据你设计图的标准来写!!!

那这个设计图的宽度dp怎么根据自己的设计图上的标准来得到呢,很简单,只要得出设计图的比例density就O98K了 

density的计算公式为:density = dpi / 160想要得到density,那就必须要先得到dpi,而dpi计算公式为:

 

好了,公式咱都有了,那么就开始套公式吧,比如我现在的设计图的分辨率为750*1334,屏幕尺寸为4.7(不知道的可以去问UI)

根据公式得出dpi= 326 ,那么density =326 /160 ≈= 2 ,很好,density有了,那么上图中的设计图的宽度dp就为 750/2 = 375

附上代码:

private static float sNoncompatDesity;
private static float sNoncompatScaledDesity;
private static  void setCustomDesity(@NonNull Activity activity, @NonNull final Application application){
    final DisplayMetrics appdisplayMetrics = application.getResources().getDisplayMetrics();
    if(sNoncompatDesity==0){
        sNoncompatDesity = appdisplayMetrics.density;
        sNoncompatScaledDesity = appdisplayMetrics.scaledDensity;
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration configuration) {
                if(configuration!=null&&configuration.fontScale>0){
                    sNoncompatScaledDesity = application.getResources().getDisplayMetrics().scaledDensity;
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }

    final float targetDesity = appdisplayMetrics.widthPixels/375;//375 设计图的宽度dp
    final float targetScaleDesity = targetDesity*(sNoncompatScaledDesity/sNoncompatDesity);
    final int targetDesityDpi = (int)(160*targetDesity);

    appdisplayMetrics.density = targetDesity;
    appdisplayMetrics.scaledDensity = targetScaleDesity;
    appdisplayMetrics.densityDpi = targetDesityDpi;

    final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
    activityDisplayMetrics.density = targetDesity;
    activityDisplayMetrics.scaledDensity = targetScaleDesity;
    activityDisplayMetrics.densityDpi = targetDesityDpi;
}

 

然后在BaseActivity中的onCreate方法中调用该方法,项目跑起来运行在手机上,好像有点毛病,适配效果有点不对头,于是多运行了几款测试机,大部分手机貌似都有这个问题,而且在其中一款手机上显示的特别小,适配的效果明显不对,怎么办,这种适配方式不行吗,于是慢慢排查问题,折腾许久,终于发现了一个不起眼的问题

final float targetDesity = appdisplayMetrics.widthPixels/375;

问题出现在这行代码中,这行代码一眼看上去好像没问题,2个数字相除得到一个float类型的结果,但是appdisplayMetrics.widthPixels这个值是int类型,375也是int类型,int整数除以int整数得到的一定是int整数原来如此,就比如说我明明预想中得到的结果应该为1.8 ,结果却给我变为了1,这怎么可能不出问题呢,所以这行代码正确写法应该是这样的:

final float targetDesity = (float)appdisplayMetrics.widthPixels/375;

再次编译运行,完美!

最终代码:

private static float sNoncompatDesity;
private static float sNoncompatScaledDesity;
private static  void setCustomDesity(@NonNull Activity activity, @NonNull final Application application){
    final DisplayMetrics appdisplayMetrics = application.getResources().getDisplayMetrics();
    if(sNoncompatDesity==0){
        sNoncompatDesity = appdisplayMetrics.density;
        sNoncompatScaledDesity = appdisplayMetrics.scaledDensity;
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration configuration) {
                if(configuration!=null&&configuration.fontScale>0){
                    sNoncompatScaledDesity = application.getResources().getDisplayMetrics().scaledDensity;
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }

    final float targetDesity = (float)appdisplayMetrics.widthPixels/375;//375 设计图的宽度dp
    final float targetScaleDesity = targetDesity*(sNoncompatScaledDesity/sNoncompatDesity);
    final int targetDesityDpi = (int)(160*targetDesity);

    appdisplayMetrics.density = targetDesity;
    appdisplayMetrics.scaledDensity = targetScaleDesity;
    appdisplayMetrics.densityDpi = targetDesityDpi;

    final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
    activityDisplayMetrics.density = targetDesity;
    activityDisplayMetrics.scaledDensity = targetScaleDesity;
    activityDisplayMetrics.densityDpi = targetDesityDpi;
}

 

到了这里,有人就要问了,如果我这些代码都写好了,那么我在xml上面如何写dp大小呢?很简单,上面我们不是根据设计图的尺寸得出了density 等于2吗,那么比如设计图上标注一个TextView字体大小为30px 。则实际填写的字体大小为: 30 /2=15dp,根据这个规则来换算出来就好了

 

使用总结:

1. 把最终代码放在BaseActivity中

2. 根据设计图尺寸得出比例density(如果实在不想算,想直接知道已知分辨率和屏幕尺寸设计图的density,请查看:https://material.io/tools/devices/,如果进不去,请翻墙)

3. 用设计图屏幕宽的分辨率/density得出该设计图宽的dp并赋值到原来的值中

4. 在BaseActivity的onCreate方法中调用

5. 在xml中使用时:dp-Size根据设计图尺寸得出的比例density的值来赋值,px-Size/density == dp-Size

6.2018.11.12日补充,已有大佬封装好了该功能,使用后个人感觉他封装的很好,大家可以移步https://github.com/JessYanCoding/AndroidAutoSize ,各位慢走不送~~~

 
 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值