Contact Us

首页 资讯正文

安卓屏幕适配踩坑笔记(手机+平板)手机平板「安卓屏幕适配踩坑笔记(手机+平板)」

发布者:yu发布时间:2025-01-09访问量:362

目前做APP的时候,尤其应用跑在平板上的时候,发现了一个比较难解决的安卓碎片化的问题:同样分辨率的平板,屏幕密度是不相同的,甚至于不同品牌的手机也是不相同的。

下面随便举了一些例子:

型号类型屏幕宽度屏幕高度屏幕密度rockchip平板192011281.5华为C5平板192012002华为C3平板12808001.275小米10手机108021202.75华为nova4手机108021083vivo手机   

屏幕上显示的单位都是以px为准的,而我们代码中一般设置的单位是dp。

换算关系如下:px=dp*density。

比如说我代码中设置一个button的高度为20dp,在华为C5平板上的高度就是40px,在rockchip平板上显示的高度就是30px。

但是这两个平板的分辨率几乎是一样的,这样就会产生一个问题,根据UI稿,如果我们按照C5平板的density来设计,那么在rockchip平板上就会显示的很大,会比设计稿大30%。

如下图所示,针对不同的分辨率创建不同的values文件夹,并且添加不同的dimens文件。而dimens针对不同的dp配置不同的px值

安卓屏幕适配踩坑笔记(手机+平板)手机平板「安卓屏幕适配踩坑笔记(手机+平板)」安卓屏幕适配踩坑笔记(手机+平板)手机平板「安卓屏幕适配踩坑笔记(手机+平板)」

使用的时候我们直接使用dipxx代替原来的dp值,如下。

 

1280x800的分辨率下,我配置的dip16=32px

1920x1080的分辨率下,我配置的dip16=48px

则上面的TextView,在1280x800展示大小为32px*32px,在1920x1080展示的大小为48px*48px

代码中所有使用dp的地方,全部改为dipxx替代。这样等于针对不同的分辨率直接使用px,从而解决了density不一致的问题。

 

附送values文件生成代码:

 

 

优点:对原生无侵入,原理简单。

缺点:

1.对原有的代码代码量较大,所以使用到dp的地方都需要替换。(可以写脚本进行这种替换)

2.横竖屏切换的时候会导致不适配。横竖屏切换的时候,上述配置文件是失效的。

 

因为横竖屏切换的时候会导致配置文件失效,这时候展示出来的界面控件大小是有问题的,所以这种方案使用了一段之后,最终被放弃。

但是如果没有横竖屏切换的需求,全部都是mainfest里面写死的横屏或者竖屏,是没有的问题。

 

上面说的是针对分辨率设置不同的配置文件,在横竖屏切换的时候有问题,那么能否按照竖屏的方式再去配置一套呢?搜了一圈,果然可以。

如下图所示,同样1920*1080分辨率情况下,密度不同,则dp值不同。如果我设置两个dp值适配的文件进行适配,则可以解决这个问题。

其中编号3中的dimens文件,大小可以设置为编号1中的1.5倍。

编号分辨率密度dp值缩放比11920*10803360121280*7202360131920*108025401.541280*7201.54801.33

w360dp设置:

安卓屏幕适配踩坑笔记(手机+平板)手机平板「安卓屏幕适配踩坑笔记(手机+平板)」

w540dp中设置:

安卓屏幕适配踩坑笔记(手机+平板)手机平板「安卓屏幕适配踩坑笔记(手机+平板)」

这里要额外说一下,这套适配和上面方案一的适配是可以同时使用的。方案二的优先级要高于方案一,即如果手机或平板同时命中方案一的分辨率和方案二的dp值时,优先按照方案二进行适配。

 

方案二其实已经满足我的需求了,因为它已经解决了同样分辨率不同密度展示不相同的问题。但是由于我之前的方案使用的是方案一,所以使用方案二的话会导致方案一完全失效,会影响所有的控件。风险性较大。

 

另外方案二还有一个缺陷,就是横竖屏切换的时候,适配的是不同的文件夹。比如我1920*1200,屏幕密度是2。那么横屏显示的时候适配的是w960dp的文件夹,竖屏显示的时候适配的是w600dp的文件夹。这时候如果我要设置宽度占横屏时屏幕的一半,则应该dip320,实际展示出来,宽度为2*1.5*320=960px,正好为屏幕的一半宽度。

这时候如果有一个屏幕分辨率是1800*1080的,屏幕密度是3的。则也适用w600dp的文件夹。这时候dip320的时候,宽度为3*1.5*320=1440,那这时候就有问题了。

 

这个是参照今日头条的一个方案,所有安卓设备最终展示在屏幕上面的都是像素px,既然是像素,那么我们代码中写的dp,sp什么的,就一定有一个地方转换为像素值,这个地方就是TypedValue类的applyDimension方法:

 

这里我们就举一个例子就好了,TextView设置字号:

如下图所示,setTextSize默认传入的是sp,调用setTextSizeInternal方法,通过TypedValue.applyDimension方法把sp转换为最终的像素值,传入setRawTextSize方法。setRawTextSize中把size设置给TextPaint,所以我们也知道了,TextPaint接收的单位是像素值。

 

OK,回归正题,如何修改像素值呢?这个很简单,都不需要反射,直接通过resources获取DisplayMetrics对象,然后直接粗暴的改掉就好了,简单的有点不可思议。由于进程是共享一个resources的,所以直接在application中进行一次设置,整个APP都生效了。我们公司的设计一般是按照360*640进行设置的,所以我只要按照这个比例去设置密度值即可:

比如:

1920*1080/1920*1200等,密度值是3

1280*720/1280*800等,密度值是2

代码如下,在闪屏页进行加载。

 

然后我就惊喜的发现,所有界面都已经生效了。

这个方案虽然好,但是使用的过程中也发现了一些问题。于是整理了一下原因和解决方案,汇总如下:

问题点1:有的时候发现密度值会失效,恢复到未修改的原始的状态