那么适配后的 density = 设备真实宽(单位px) / 360,接下来只需要把我们计算好的 density 在系统中修改下即可,代码实现如下:
同时在 Activity#onCreate 方法中调用下。代码比较简单,也没有涉及到系统非公开api的调用,因此理论上不会影响app稳定性。
于是修改后上线灰度测试了一版,稳定性符合预期,没有收到由此带来的crash,但是收到了很多字体过小的反馈:
原因是在上面的适配中,我们忽略了DisplayMetrics#scaledDensity的特殊性,将DisplayMetrics#scaledDensity和DisplayMetrics#density设置为同样的值,从而某些用户在系统中修改了字体大小失效了,但是我们还不能直接用原始的scaledDensity,直接用的话可能导致某些文字超过显示区域,因此我们可以通过计算之前scaledDensity和density的比获得现在的scaledDensity,方式如下:
但是测试后发现另外一个问题,就是如果在系统设置中切换字体,再返回应用,字体并没有变化。于是还得监听下字体切换,调用 Application#registerComponentCallbacks 注册下 onConfigurationChanged 监听即可。
因此最终方案如下:
当然以上代码只是以设计图宽360dp去适配的,如果要以高维度适配,可以再扩展下代码即可。
适配前后和设计图对比
适配后各机型的显示效果:
// 今日头条的屏幕适配方案 // 通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值,这样就解决了所有的适配问题 // @param activity // @param application private static float sNoncompatDensity; private static float sNoncompatScaledDensity; public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application){ DisplayMetrics appDisplayMetrics=application.getResources().getDisplayMetrics(); if (sNoncompatDensity==0){ sNoncompatDensity=appDisplayMetrics.density; sNoncompatScaledDensity=appDisplayMetrics.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() { } }); } float targetDensity=appDisplayMetrics.widthPixels/360; float targetScaleDensity=targetDensity*(sNoncompatScaledDensity/sNoncompatDensity); int targetDensityDpi=(int)(160*targetDensity); appDisplayMetrics.density=targetDensity; appDisplayMetrics.scaledDensity=targetScaleDensity; appDisplayMetrics.densityDpi=targetDensityDpi; final DisplayMetrics activityDisplayMetrics=activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density=targetDensity; activityDisplayMetrics.scaledDensity=targetScaleDensity; activityDisplayMetrics.densityDpi=targetDensityDpi; }