Android屏幕适配的示例分析(android,移动开发)

时间:2024-05-03 08:23:40 作者 : 石家庄SEO 分类 : 移动开发
  • TAG :

测试与思考

不得不说今日头条的大神们的想法真的非常独到,成本极其低廉,还特别好用。他们给出的最终方案是这样的:

privatestaticfloatsRoncompatDennsity;privatestaticfloatsRoncompatScaledDensity;privatevoidsetCustomDensity(@NonNullActivityactivity,final@NonNullApplicationapplication){//applicationfinalDisplayMetricsappDisplayMetrics=application.getResources().getDisplayMetrics();if(sRoncompatDennsity==0){sRoncompatDennsity=appDisplayMetrics.density;sRoncompatScaledDensity=appDisplayMetrics.scaledDensity;application.registerComponentCallbacks(newComponentCallbacks(){@OverridepublicvoidonConfigurationChanged(ConfigurationnewConfig){if(newConfig!=null&&newConfig.fontScale>0){sRoncompatScaledDensity=application.getResources().getDisplayMetrics().scaledDensity;}}@OverridepublicvoidonLowMemory(){}});}//计算宽为360dp同理可以设置高为640dp的根据实际情况finalfloattargetDensity=appDisplayMetrics.widthPixels/360;finalfloattargetScaledDensity=targetDensity*(sRoncompatScaledDensity/sRoncompatDennsity);finalinttargetDensityDpi=(int)(targetDensity*160);appDisplayMetrics.density=targetDensity;appDisplayMetrics.densityDpi=targetDensityDpi;appDisplayMetrics.scaledDensity=targetScaledDensity;//activityfinalDisplayMetricsactivityDisplayMetrics=activity.getResources().getDisplayMetrics();activityDisplayMetrics.density=targetDensity;activityDisplayMetrics.densityDpi=targetDensityDpi;activityDisplayMetrics.scaledDensity=targetScaledDensity;}

看到这篇文章之后我赶紧就写了一个demo测试了一下,发现了一点小问题。我们UI给出的设计图尺寸为1334*720,如果我按照宽度作为适配标准的话,按照设计图720px的宽度,屏幕的宽度应为360dp,也就是这样:

finalfloattargetDensity=appDisplayMetrics.widthPixels/360;

这样做的话宽度适配的比例是没有任何问的,但是我在想,如果需要以高度来做适配(也就是内容刚好纵向填充全屏)的话,是不是改成这样就可以了:

finalfloattargetDensity=appDisplayMetrics.heightPixels/667;

但是运行之后发现,高度上的差异很大,运行在不同分辨率和尺寸的手机上,页面中的每一部分内容在纵向上的比例不尽相同,没有达到很好的适配的效果。思考了许久过后我发现一个问题:我手边的测试机的宽度是两个720和两个1080,而高度有1280,1440,1780和一个全面屏的2160。Android的开原性导致了Android设备的尺寸的碎片化太严重,而通过查看手机的尺寸参数会发现,如果用这四个手机来测试的话,宽度可以直接整除,而高度不可以(并且我手边的测试机的宽度也可以整除,如果有宽度没法整除的手机呢?)。但是用今日头条给出的方法,做除法后结果会取整,那会不会是由于用纵向计算出来的density取整影响了精度,从而导致了效果不尽人意呢?

问题修复

发现上述问题之后我就着手去修改,将计算结果取余后在赋值给targetDensity,经过一下午的反复测试与实验,我重新修改了targetDensity的计算方法:

floattargetDensity=0;try{Doubledivision=Operation.division(appDisplayMetrics.heightPixels,667);//由于手机的长宽不尽相同,肯定会有除不尽的情况,有失精度,所以在这里把所得结果做了一个保留两位小数的操作DecimalFormatdf=newDecimalFormat("0.00");Strings=df.format(division);targetDensity=Float.parseFloat(s);}catch(NumberFormatExceptione){e.printStackTrace();}

经测试后发现,这样取两位小数计算过后,高度上的适配结果让人非常满意。可是还有一个问题,我们一般来说做适配都是以手机的宽度为基准,但是一个app里面避免不了偶尔一两个页面是按照高度为基准(就是内容纵向填充全屏的页面)做适配的。但是上述方法只能保证一个方向,那我就让它可以自由的切换适配的基准方向不就好了。

最终方案

继续修改之后我得到了最终的方案,修改过后这个类中的所有内容如下:

privatestaticfloatappDensity;privatestaticfloatappScaledDensity;privatestaticDisplayMetricsappDisplayMetrics;//此方法在Application的onCreate方法中调用Density.setDensity(this);publicstaticvoidsetDensity(@NonNullApplicationapplication){//获取application的DisplayMetricsappDisplayMetrics=application.getResources().getDisplayMetrics();if(appDensity==0){//初始化的时候赋值(只在Application里面初始化的时候会调用一次)appDensity=appDisplayMetrics.density;appScaledDensity=appDisplayMetrics.scaledDensity;//添加字体变化的监听application.registerComponentCallbacks(newComponentCallbacks(){@OverridepublicvoidonConfigurationChanged(ConfigurationnewConfig){//字体改变后,将appScaledDensity重新赋值if(newConfig!=null&&newConfig.fontScale>0){appScaledDensity=application.getResources().getDisplayMetrics().scaledDensity;}}@OverridepublicvoidonLowMemory(){}});}//调用修改density值的方法(默认以宽度作为基准)setAppOrientation(null,AppUtils.WIDTH);}//此方法用于在某一个Activity里面更改适配的方向Density.setOrientation(mActivity,"width/height");publicstaticvoidsetOrientation(Activityactivity,Stringorientation){setAppOrientation(activity,orientation);}/***targetDensity*targetScaledDensity*targetDensityDpi*这三个参数是统一修改过后的值**orientation:方向值,传入width或height*/privatestaticvoidsetAppOrientation(@NullableActivityactivity,Stringorientation){floattargetDensity=0;try{Doubledivision;//根据带入参数选择不同的适配方向if(orientation.equals("height")){//appDisplayMetrics.heightPixels/667division=Operation.division(appDisplayMetrics.heightPixels,667);}else{division=Operation.division(appDisplayMetrics.widthPixels,360);}//由于手机的长宽不尽相同,肯定会有除不尽的情况,有失精度,所以在这里把所得结果做了一个保留两位小数的操作DecimalFormatdf=newDecimalFormat("0.00");Strings=df.format(division);targetDensity=Float.parseFloat(s);}catch(NumberFormatExceptione){e.printStackTrace();}floattargetScaledDensity=targetDensity*(appScaledDensity/appDensity);inttargetDensityDpi=(int)(160*targetDensity);/*******在这里将修改过后的值赋给系统参数**(因为最开始初始化的时候,activity为null,所以只设置application的值就可以了...*所以在这里判断了一下,如果传有activity的话,再设置Activity的值)*/if(activity!=null){DisplayMetricsactivityDisplayMetrics=activity.getResources().getDisplayMetrics();activityDisplayMetrics.density=targetDensity;activityDisplayMetrics.scaledDensity=targetScaledDensity;activityDisplayMetrics.densityDpi=targetDensityDpi;}else{appDisplayMetrics.density=targetDensity;appDisplayMetrics.scaledDensity=targetScaledDensity;appDisplayMetrics.densityDpi=targetDensityDpi;}}

这是修改之后的所有内容,不懂的地方可以看一下里面的注释,在里面我是默认的以宽度来作为基准(这是在Activity中设置的方法,存在于此Activity下的fragment,dialog和PopupWindow都会受到此效果的影响,也就是说,在Activity中设置一次之后,Activity下的其他子View都无需再设置一次)。

使用方法

自己创建一个类,将最终方案里面的代码复制粘贴就可以使用了

使用方法:在Application的onCreate()方法中

Android屏幕适配的示例分析

如果只是适配一个方向的话,只设置这一句就可以了(我在utils里面设置了默认按照宽度适配,可以根据自己的需求修改默认的适配方向,见下图)

Android屏幕适配的示例分析

若app中有某一个页面需要纵向适配的话:

/****由于是个人封装,此方法需要写在onCreate()中的setContentView()方法前面,切换方向的效果才会生效*/@OverridepublicvoidsetOrientation(){Density.setOrientation(this,AppUtils.HEIGHT);}/****如果在一个Activity里面切换了适配方向的话,需要在destroy里面将方向设置为默认的方向,*因为切换方向修改的是Activity的值,但是application的也会覆盖掉(原因还没有搞清楚...),*权衡利弊之后就在onDestroy这个生命周期里面重新初始化了一下方向(因为用高度作为适配基准的页面*少之又少,这样可以***程度的减少对程序功能性的影响)*/@OverrideprotectedvoidonDestroy(){super.onDestroy();Density.setOrientation(this,AppUtils.WIDTH);}

由于在某一个Activity里面切换方向之后,我修改掉的是Activity中的值(activityDensity),但是返回再点击其他页面之后发现其他页面的适配方向也被修改掉了,于是乎权衡利弊之后我就用了这个相对来说影响最小的办法:在需要修改适配方向的Activity中的onDetroy生命周期里面,再手动将方向改成默认。。。(捣鼓了很久实在是想不到更好的办法了,如果各位看官有其他的好办法可以给我留言)。

Android屏幕适配的示例分析

***贴出纵向适配的效果图,页面中蓝色背景的TextView高度是固定的150dp(只是我自己写的一个很简单的页面,不要嫌丑。。。):

Android屏幕适配的示例分析

敲黑板!!!

用此方法写适配,只需要一个dimens文件,一个layout文件就足矣,在xml布局中直接只用dp就可以了(Android P的刘海屏需要单独适配layout,全面屏手机可以隐藏的虚拟按键似乎也需要单独适配。。。)

Android屏幕适配的示例分析
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Android屏幕适配的示例分析的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:Android中的四大组件以及应用场景是什么下一篇:

13 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18