亚博yabo888vip网页版登录_Android屏幕适配很难嘛?其实也就那么回事

产品时间:2022-09-24 01:02

简要描述:

前言作为一个Android开发人员,你还在为了适配种种尺寸的屏幕而苦恼吗?你还在为了泛起一个新的机型而修改着数不尽的dimens和layout吗?你还在为了UI给的奇葩尺寸的设计图而绞尽奶汁盘算距离吗?如果你为了这些事情而苦恼,那么看完这篇文章,希望可以帮你淘汰开发时间,减缓生命的流逝速度。不知道大家有没有看过前一段时间今日头条技术团队揭晓的一篇关于Android屏幕适配的文章:一种极低成本的Android屏幕适配方式。...

推荐产品
详细介绍
本文摘要:前言作为一个Android开发人员,你还在为了适配种种尺寸的屏幕而苦恼吗?你还在为了泛起一个新的机型而修改着数不尽的dimens和layout吗?你还在为了UI给的奇葩尺寸的设计图而绞尽奶汁盘算距离吗?如果你为了这些事情而苦恼,那么看完这篇文章,希望可以帮你淘汰开发时间,减缓生命的流逝速度。不知道大家有没有看过前一段时间今日头条技术团队揭晓的一篇关于Android屏幕适配的文章:一种极低成本的Android屏幕适配方式。

亚博yabo888网页登录

前言作为一个Android开发人员,你还在为了适配种种尺寸的屏幕而苦恼吗?你还在为了泛起一个新的机型而修改着数不尽的dimens和layout吗?你还在为了UI给的奇葩尺寸的设计图而绞尽奶汁盘算距离吗?如果你为了这些事情而苦恼,那么看完这篇文章,希望可以帮你淘汰开发时间,减缓生命的流逝速度。不知道大家有没有看过前一段时间今日头条技术团队揭晓的一篇关于Android屏幕适配的文章:一种极低成本的Android屏幕适配方式。

没有看过的朋侪可以先看看相识一下再回来,可以更好的明白。我是无意中点开的这篇文章,可是看过之后眼前一亮-------Android屏幕适配要是真的这么简朴,那些辛辛苦苦没日没夜做适配的前辈们是不是死得太惨了。测试与思考不得不说今日头条的大神们的想法真的很是独到,成本极其低廉,还特别好用。

他们给出的最终方案是这样的: private static float sRoncompatScaledDensity; private void setCustomDensity(@NonNull Activity activity, final @NonNull Application application) { //application final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (sRoncompatDennsity == 0) { sRoncompatDennsity = appDisplayMetrics.density; sRoncompatScaledDensity = appDisplayMetrics.scaledDensity; application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //盘算宽为360dp 同理可以设置高为640dp的凭据实际情况 final float targetDensity = appDisplayMetrics.widthPixels / 360; final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity); final int targetDensityDpi = (int) (targetDensity * 160); appDisplayMetrics.density = targetDensity; appDisplayMetrics.densityDpi = targetDensityDpi; appDisplayMetrics.scaledDensity = targetScaledDensity; //activity final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; activityDisplayMetrics.scaledDensity = targetScaledDensity; } 看到这篇文章之后我赶快就写了一个demo测试了一下,发现了一点小问题。我们UI给出的设计图尺寸为1334*720,如果我根据宽度作为适配尺度的话,根据设计图720px的宽度,屏幕的宽度应为360dp,也就是这样:final float targetDensity = appDisplayMetrics.widthPixels / 360; 这样做的话宽度适配的比例是没有任何问的,可是我在想,如果需要以高度来做适配(也就是内容恰好纵向填充全屏)的话,是不是改成这样就可以了:final float targetDensity = appDisplayMetrics.heightPixels / 667; 可是运行之后发现,高度上的差异很大,运行在差别分辨率和尺寸的手机上,页面中的每一部门内容在纵向上的比例不尽相同,没有到达很好的适配的效果。思考了许久事后我发现一个问题:我手边的测试机的宽度是两个720和两个1080,而高度有1280,1440,1780和一个全面屏的2160。

亚博yabo888网页登录

Android的开原性导致了Android设备的尺寸的碎片化太严重,而通过检察手机的尺寸参数会发现,如果用这四个手机来测试的话,宽度可以直接整除,而高度不行以(而且我手边的测试机的宽度也可以整除,如果有宽度没法整除的手机呢?)。可是用今日头条给出的方法,做除法后效果会取整,那会不会是由于用纵向盘算出来的density取整影响了精度,从而导致了效果不尽人意呢?问题修复发现上述问题之后我就着手去修改,将盘算效果取余后在赋值给targetDensity,经由一下午的重复测试与实验,我重新修改了targetDensity的盘算方法:float targetDensity = 0; try { Double division = Operation.division(appDisplayMetrics.heightPixels, 667); //由于手机的长宽不尽相同,肯定会有除不尽的情况,有失精度,所以在这里把所得效果做了一个保留两位小数的操作 DecimalFormat df = new DecimalFormat("0.00"); String s = df.format(division); targetDensity = Float.parseFloat(s); } catch (NumberFormatException e) { e.printStackTrace(); } 经测试后发现,这样取两位小数盘算事后,高度上的适配效果让人很是满足。

可是另有一个问题,我们一般来说做适配都是以手机的宽度为基准,可是一个app内里制止不了偶然一两个页面是根据高度为基准(就是内容纵向填充全屏的页面)做适配的。可是上述方法只能保证一个偏向,那我就让它可以自由的切换适配的基准偏向不就好了。最终方案继续修改之后我获得了最终的方案,修悔改后这个类中的所有内容如下:private static float appDensity; private static float appScaledDensity; private static DisplayMetrics appDisplayMetrics; //此方法在Application的onCreate方法中挪用 Density.setDensity(this); public static void setDensity(@NonNull Application application) { //获取application的DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (appDensity == 0) { //初始化的时候赋值(只在Application内里初始化的时候会挪用一次) appDensity = appDisplayMetrics.density; appScaledDensity = appDisplayMetrics.scaledDensity; //添加字体变化的监听 application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { //字体改变后,将appScaledDensity重新赋值 if (newConfig != null && newConfig.fontScale > 0) { appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //挪用修改density值的方法(默认以宽度作为基准) setAppOrientation(null, AppUtils.WIDTH); } //此方法用于在某一个Activity内里更改适配的偏向 Density.setOrientation(mActivity, "width/height"); public static void setOrientation(Activity activity, String orientation) { setAppOrientation(activity, orientation); } /** * targetDensity * targetScaledDensity * targetDensityDpi * 这三个参数是统一修悔改后的值 * * orientation:偏向值,传入width或height */ private static void setAppOrientation(@Nullable Activity activity, String orientation) { float targetDensity = 0; try { Double division; //凭据带入参数选择差别的适配偏向 if (orientation.equals("height")) { //appDisplayMetrics.heightPixels/667 division = Operation.division(appDisplayMetrics.heightPixels, 667); } else { division = Operation.division(appDisplayMetrics.widthPixels, 360); } //由于手机的长宽不尽相同,肯定会有除不尽的情况,有失精度,所以在这里把所得效果做了一个保留两位小数的操作 DecimalFormat df = new DecimalFormat("0.00"); String s = df.format(division); targetDensity = Float.parseFloat(s); } catch (NumberFormatException e) { e.printStackTrace(); } float targetScaledDensity = targetDensity * (appScaledDensity / appDensity); int targetDensityDpi = (int) (160 * targetDensity); /** * * 最后在这里将修悔改后的值赋给系统参数 * * (因为最开始初始化的时候,activity为null,所以只设置application的值就可以了... * 所以在这里判断了一下,如果传有activity的话,再设置Activity的值) */ if (activity != null) { DisplayMetrics activityDisplayMetrics = 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()方法中image.png如果只是适配一个偏向的话,只设置这一句就可以了(我在utils内里设置了默认根据宽度适配,可以凭据自己的需求修改默认的适配偏向,见下图)若app中有某一个页面需要纵向适配的话:/** * * 由于是小我私家封装,此方法需要写在onCreate()中的setContentView()方法前面,切换偏向的效果才会生效 */ @Override public void setOrientation() { Density.setOrientation(this, AppUtils.HEIGHT); } /** * * 如果在一个Activity内里切换了适配偏向的话,需要在destroy内里将偏向设置为默认的偏向, * 因为切换偏向修改的是Activity的值,可是application的也会笼罩掉(原因还没有搞清楚...), * 权衡利弊之后就在onDestroy这个生命周期内里重新初始化了一下偏向(因为用高度作为适配基准的页面 * 少之又少,这样可以最大水平的淘汰对法式功效性的影响) */ @Override protected void onDestroy() { super.onDestroy(); Density.setOrientation(this, AppUtils.WIDTH); } 由于在某一个Activity内里切换偏向之后,我修改掉的是Activity中的值(activityDensity),可是返回再点击其他页面之后发现其他页面的适配偏向也被修改掉了,于是乎权衡利弊之后我就用了这个相对来说影响最小的措施:在需要修改适配偏向的Activity中的onDetroy生命周期内里,再手动将偏向改成默认。

(捣鼓了良久实在是想不到更好的措施了,如果列位看官有其他的好措施可以给我留言)。最后贴出纵向适配的效果图,页面中蓝色配景的TextView高度是牢固的150dp(只是我自己写的一个很简朴的页面,不要嫌丑。):敲黑板!!!用此方法写适配,只需要一个dimens文件,一个layout文件就足矣,在xml结构中直接只用dp就可以了(Android P的刘海屏需要单独适配layout,全面屏手机可以隐藏的虚拟按键似乎也需要单独适配。

亚博yabo888vip网页版登录

)结语由于是自己写的demo,还没有大面积测试,要是列位看官有条件大规模测试的话,泛起什么问题可以反馈给我,我们可以一起讨论该如何修改,配合进步。有写的欠好的地方接待指正,以后还会继续努力多写文章的,好的工具需要分享。

【附】相关架构及资料资料免费领取方式:转发后关注我后台私信关键词【资料】获取!。


本文关键词:亚博,yabo888vip,网页,版,登录,Android,屏幕,适配,亚博yabo888vip网页版登录

本文来源:亚博yabo888网页登录-www.0531byw.com

产品咨询

留言框

  • 产品:

  • 您的单位:

  • 您的姓名:

  • 联系电话:

  • 详细地址:

  • 留言内容:

在线客服 联系方式 二维码

电话

0493-53922365

扫一扫,关注我们