Android dp方式的屏幕适配-原理(后期补充完整讲解)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fesdgasdgasdg/article/details/82054971

Android dp方式的屏幕适配-原理

传统所说的屏幕适配,其实是针对不同屏幕的UI尺寸适配,即在编写页面时使用了具体的dp、sp值后导致的其他问题。
我之前写过一些相关的文章和工具插件,也收到了很多网友的反馈。
今天特编写此篇博客,重新整理以前的思路,同时也融入我近期更深刻的理解和总结,完整解答各位网友的疑惑。

友情链接,感谢鸿神提供的思路。
张鸿洋的《Android 屏幕适配方案》:

https://blog.csdn.net/lmj623565791/article/details/45460089

和其他大神的相关博客,自行搜索

我的前几篇文章:
Android屏幕适配dp、px两套解决办法

https://blog.csdn.net/fesdgasdgasdg/article/details/52325590

Android dp方式的屏幕适配工具使用(bat批处理方式)

https://blog.csdn.net/fesdgasdgasdg/article/details/78107653

Android dp方式的屏幕适配工具使用(Android Studio插件方式)

https://blog.csdn.net/fesdgasdgasdg/article/details/78108169

Android dp方式的屏幕适配工具使用(一些疑惑和注意事项)

https://blog.csdn.net/fesdgasdgasdg/article/details/78133821

 

GitHub源码地址:https://github.com/mengzhinan/PhoneScreenMatch

GitHub插件源码地址:https://github.com/mengzhinan/ScreenMatch

IDEA插件包地址:https://plugins.jetbrains.com/plugin/10058-screenmatch

 

 

我们按照下面问题的纲要和对应解答,来一步步思考和理解我的解决思路。

1、背景1:google建议我们在编码时使用计量单位为dp、sp、match_parent或wrap_content。

*单位dp和sp。
上述google给我们的建议,都知道。
顺便露一句:1dp=(1/160*)(inch)=(2.54/160)(cm)。在任何设备上都是定长,除非设备参数被厂商修改。

[dp等于物理定长]
官网链接:

https://developer.android.google.cn/guide/practices/screens_support

 

 

 

2、对于《多屏幕适配》,究竟是出了什么疑难问题?(需要产品介入抉择)


*在不同的宽度dp的手机上需要实现等比缩放。

如上图。我们按照google的建议,编码UI时,使用dp的方式硬编码,那么在不同宽度dp的手机上的视觉效果会有误差,感觉布局向某一侧挤压了。
当然,需要说明的是,控件的物理长度是不变的,因为我上面提到dp等于现实世界的物理长度。

而不同手机的宽度dp值可能是不一样的,这就是问题所在。

 

 

如果产品需要上图2中的效果,实现不同宽度dp的手机展现的UI整体布局一致,怎么办?
这就是多屏幕适配UI的问题。
当然,产品乐意图1的效果,有点整体偏差无所谓,那就不需要看下文了,over。

此时,我们明确一个需求,UI在不同的宽度dp的手机上需要实现等比缩放,达到UI整体效果一致。

 

3、背景2:google提供了资源目录的限定符规则。


*基于google的sw<N>dp限定符规则,提供多套dimens.xml文件。
即google允许在项目 res/ 目录内支持的资源目录创建带有限定符规则的同名目录。

如:drawable-hdpi,layout-land,strings-en.xml等。
官网链接:

https://developer.android.google.cn/guide/topics/resources/providing-resources

本文需要提到的是sw<N>dp限定符。请详细阅读官网文档的此章节。

在我的案例中,此限定符作用在values目录上,如:

values-sw384dp
values-sw410dp
values-sw480dp

手机系统在运行期间,根据手机实际的宽度dp值,去寻找指定宽度dp的values目录,然后使用里面的一套资源作用在UI上。比喻手机运行时的实际宽度dp值是410,那么系统会使用values-sw410dp下面的资源作用在app上。

但需要注意一点。如果你的手机宽度dp值为410.69。或许你可以生成values-sw410.59dp这个目录来做适配,我没试过。个人建议你写成values-sw410dp,而不是values-sw410.59dp或values-sw411dp。因为系统会向下寻找等于或小于410.59的值的values目录,直到默认的values目录为止。

手机宽度dp值计算方法之一:

DisplayMetrics dm = getResources().getDisplayMetrics();
//手机宽度dp值 = 手机实际宽度像素px / 手机屏幕密度比
float widthDP = dm.widthPixels / dm.density;

sw的意思是smallestWidth,即手机的最小宽度dp值。
其实更确切的说,是指手机宽度和高度的dp值中最小者。
对于常规手机而言,肯定是宽度dp值较小。如果手机切换成横屏了,那么就是高度dp值较小。
但无论是横屏还是竖屏状态,最小者的dp值是不变的。即无论横竖屏状态,此手机都只会寻找对应宽度dp的values目录下的相关文件(dimens.xml)来处理UI尺寸问题,而避免了横竖屏切换时UI变形问题。

比喻你的手机宽度是360dp,高度是640dp。那么无论是横屏还是竖屏时,程序运行时都会寻找values-sw360dp的目录(如果有)来作用在UI上。而不会是竖屏使用values-sw360dp,横屏时使用values-sw640dp了,自己实验。
如果你不希望这个结果,那么你可以选择values-w<N>dp的目录方式,具体参考上面官网文档说明,自己实验。


此时,我们理解了google官方的原理。剩下的,我们需要定义dimen变量,并生成对应手机宽度dp的dimens.xml文件来作用在UI上,实现UI等比缩放效果。

 

4、手机宽度360dp和dp_360的由来,基础dimen变量键值对定义。


*屏幕宽度等分为360份,认为dp_360变量表示沾满屏幕,等价于match_parent。

在众多的主流尺寸手机中,如1920x1080、1280x720等,测试发现,他们的手机宽度dp值是360dp,覆盖范围达到90%,但是不包括现在流行的全面屏、刘海屏(没测试)。设计师提供的标注图一般也是720px或者1080px的,我们拿来转换为对应的dp值时也是默认基于360的基准值,如果让设计师帮忙转换也是一样的结果。
即无论是对传统尺寸手机宽度的计算,或者是开发期间开发和设计的共同认知,都认为是360dp为手机屏幕宽度值。
为了迎合这个标准,便于计算,所以我也就以360作为适配方案的基准值,即360的由来。

根据上面的潜认识,我把屏幕宽度的dp值定为dp_360这个变量(注意是变量,不是360dp这个固定值),
即把任意手机的屏幕等分为360份,
然后在默认的values/dimens.xml文件中定义了一套变量,变量名和变量值是1:1关系的。
如:

好处是:
a、就算只使用values/dimens.xml文件,也可适配90%的传统手机。
b、变量的定义直观易懂,屏幕等分为360份,每一份为dp_1,沾满屏幕宽度为dp_360。
c、便于转换设计图px为dp值。
d、避免硬编码,便于统一管理。就算不使用我的适配方案。


5、结合values/dimens.xml文件的dp_xxx变量键值对和sw<N>dp规则,生成其他dimens.xml文件。


*等比缩放dimens.xml的键值对的值。

例如:我有一个宽度为360dp和720dp的手机,如何基于已适配的360dp,再来生成720dp的dimens.xmla文件呢?
手机宽度dp值从360变化到了720,增加了2倍,那么把手机宽度为360dp的dimens.xml文件中的每一个dimen值乘以2,变量名(键值)不变,是不是就实现了原理?

比喻一个按钮宽度layout_width="@dimen/dp_180",在360dp宽度的手机上实际值是180dp,刚好是手机宽度的一半;在720dp宽度的手机上实际值是360dp,还是手机宽度的一半。
等比缩放效果[所得即所见]。

总算知道原理了,好用。但是总不能我手写dimen文件、手动乘法计算值吧?
当然,我有工具啊。请关注文章开头的连接~~~~~~~
1、bat执行jar包的批处理方式。
2、Android Studio插件方式。

 

6、针对某未知宽度dp值的手机,如何适配或取消适配?


*根据手机的宽度dp值,生成对应的values目录和dimens.xml文件。

如果确定要适配某手机,必须得知道该手机的实际运行时宽度dp值。
然后Android开发这边得到这个dp值,工具生成对应的values和dimens.xml文件即可。
无需修改页面或者java类的代码,但是需要重新发版了。

若如想对640dp宽度的手机UI取消适配,怎么办?
仅仅只需要删除 values-sw640dp目录和子文件即可。
无需修改代码,但是需要重新发版了。

当然了,未覆盖到的范围肯定是没有处理UI等比缩放适配的了。这点是硬伤。

 


7、如何根据设计提供的px标注图,转换为dimens.xml中的dimen变量?


*除以基准值360,压缩到手机可视范围内。

常规的,设计会给宽度为1080或720px的图。
我们假定以宽度755px的图为例。
已知,设计给的图尺寸宽高为755px-1265px,其中一个按钮的像素px值宽高为100px-50px,
怎么在基于360等份的手机上编写按钮的dp值呢?

高度先不说。
基于宽度,设计图755px,要压缩到dp_360的范围内。压缩比例=755/360=2.1(约)。
即设计图内的所有内容,都要压缩2.1倍,才能用上基于dp_360范围的变量。

搜嘎

按钮宽度压缩2.1倍,等于100/2.1=dp_48(约)(变量,不是具体的dp值)
类推,按钮高度,等于50/2.1=dp_24
上面计算的约等于,取整或四舍五入都可以,接近即可。

之所以建议设计给出的设计图为360的倍数,如720或1080,那是因为除以360基准值,得到的压缩比例为整数。那么后续我们在设置控件的宽高时就不用四舍五入得到近似值了。

 


8、基于宽度适配,忽略高度。


*基于宽度360等份的适配,高度自行使用ScrollView。

上面说到,基于设计图的宽度,压缩到360等份范围的手机屏幕内。
但是注意,设计图上的内容都保留了宽高比不变,即内容不会变形。

那么又有另外一个问题,由于保证了内容宽高比不变,是不是会有些手机的屏幕无法容纳整张设计图内容?
对。!!!!!你自己使用ScrollView滚动吧。我要是限制高度,那么在有些异形手机上必然会出现控件的高度挤压或拉伸。并且上例中,控件的高度计算就不能使用宽度的压缩比例了。这样就更复杂,或者适配出的效果会更恶心了。

 

总结:

*把屏幕宽度等分成360份,实现UI在不同大小的手机上等比缩放。

我使用的values目录限定符规则是sw<N>dp,上述提到的手机宽度dp值都指最小宽度,即手机宽度、高度dp值中的较小者,与当前横、竖屏状态无关。

如果你使用的限定符规则为w<N>dp,则宽度仅仅指代当前横、竖屏状态中的"宽度"dp值。横、竖屏切换时"宽度"dp值会变化,系统会使用对应变化的values目录下的资源。

手机、平板、电视开发都可以使用这套适配方案,但是使用的UI设计图只能是针对各自类型的。例如,做电视开发时,只能使用针对电视而给出的UI设计图,而不能使用手机的UI设计图。

针对宽度dp值做屏幕适配时,建议不要其他领域的宽度dp值,即针对平板而开发的app,可以适配平板可能出现的其他宽度dp值,但是就不要添加手机或电视可能出现的宽度dp值了。针对平板的app运行在电视或手机上,UI本身就不搭调,适配了宽度dp值又有何用?

有点:工具生成,无需修改代码。添加或移除方便。

缺点:是否是产品需要的效果?无法覆盖全部机型。

 

 

感谢QQ网友Alpha的优秀建议


参考文档:

https://developer.android.google.cn/guide/topics/resources/providing-resources

https://developer.android.google.cn/guide/practices/screens_support

 

 

 

展开阅读全文

没有更多推荐了,返回首页