Android 屏幕适配方案

前言

由于我之前是在一些设备原厂工作的只需要负责sdk的工作以及去给客户驻点开发的,基本不会涉及到屏幕适配,就算是客户那边也是固定的一个Android设备不需要适配;随着我离职之后去面试别的公司,人家一问到我屏幕适配时候我回答不出来,故此我花了些时间研究网上所说的屏幕适配,然后我总结借鉴了一下。

屏幕分辨率限定符与 smallestWidth 限定符适配原理

屏幕分辨率限定符适配原理

屏幕分辨率限定符适配需要在 res 文件夹下创建各种屏幕分辨率对应的 values-xxx 文件夹,如下图:


这样设计图里面显示多少px就可以这么写@dimen/x720或者@dimen/y720,相应的屏幕配比会自动加载相应配比的资源文件,

UI设计的尺寸是多少那就按照那个比例为基准生成对应的资源,比如UI给的是720*1280的(这个单位是px,dpi=160) 然后我就会以那个为基准生成一套资源文件


代码在MakeXml,然后UI设计上标志是多少px,在资源引用时候就使用多少px


缺点:这个方案缺点很明显,只适用常规的手机屏幕尺寸。

这个方案的还有鸿洋老铁的https://blog.csdn.net/lmj623565791/article/details/45460089

效果图:


320*480


576*1027


720*1280

smallestWidth 限定符 适配原理

smallestWidth 限定符适配原理与屏幕分辨率限定符适配原理一样,系统都是根据限定符去寻找对应的 dimens.xml 文件。例如程序运行在最小宽度为 360dp 的设备上,系统会自动找到对应的 values-sw360dp 文件夹下的 dimens.xml 文件。区别就在于屏幕分辨率限定符适配是拿 px 值等比例缩放,而 smallestWidth 限定符适配是拿 dp 值来等比缩放而已。需要注意的是“最小宽度”是不区分方向的,即无论是宽度还是高度,哪一边小就认为哪一边是“最小宽度”。如下分别为最小宽度为 360dp 与最小宽度为 640dp 所对应的 dimens.xml 文件:


获取设备最小宽度代码为:

DisplayMetrics dm = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(dm);

int heightPixels = ScreenUtils.getScreenHeight(this);

int widthPixels = ScreenUtils.getScreenWidth(this);

float density = dm.density; float heightDP = heightPixels / density;

float widthDP = widthPixels / density;

float smallestWidthDP;

if(widthDP < heightDP) {

    smallestWidthDP = widthDP;

}else {

    smallestWidthDP = heightDP;

}

ScreenUtils——>ScreenUtils

使用步骤

1、以设计图最小宽度(单位为 dp)作为基准值,生成所有设备对应的 dimens.xml 文件

    这个可以使用工具ScreenMatch工具,具体怎么使用我这里就不解释了,网上很多资料

2、根据设计图标注,在布局写上对应的值。

设计图标注多少 dp,布局中就写多少 dp ,非常方便!

如果需要动态设置尺寸

/*获取sp值*/

float pxValue = getResources().getDimension(R.dimen.sp_15);//获取对应资源文件下的sp值

int spValue = ConvertUtils.px2sp(this, pxValue);//将px值转换成sp值

mTvShowParams.setTextSize(spValue);//设置文字大小 /*获取dp值*/

float pxValue2 = getResources().getDimension(R.dimen.dp_360);//获取对应资源文件下的dp值

int dpValue = ConvertUtils.px2dp(this, pxValue2);//将px值转换成dp值

使用步骤总结

说了这么多,其实只需要简单的 2 步:

以设计图最小宽度(单位为 dp)作为基准值,利用插件生成所有设备对应的 dimens.xml 文件

根据设计图标注,标注多少 dp,布局中就写多少dp,格式为@dimen/dp_XX。(注意:UI给到的图如果是px单位的话你就得换算成dp单位的,例如:UI给的是1920*1080 单位是px然后你问清楚这个是对应320dp*480dp的屏幕还是哪一款,最后是根据那个dp来标注的,个人理解,比如我那个“益糯健康这个控件距离顶部是126px,但是以dp标记缺失63dp”

缺点:宽度可以适配了但是高度没办法,


距离底部变长了

ConstraintLayout新布局 具体鸿洋老铁

鸿洋 AutoLayout全新的适配方式 堪称适配终结者

AutoLayout我就不介绍了  原文肯定讲的更好听

今日头条适配方案

因为Android中的dp在渲染前会将dp转换成px,计算公式:

px = density * dp;

density = dpi/160;

px = dp * (dpi/160);

屏幕尺寸、分辨率】像素密度三者关系


举个例子:屏幕分辨率为:1920*1080,屏幕尺寸为5吋的话,那么dpi为440。

这样会遇到一些问题:假设我们UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用dp也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足360dp,这时就会导致按360dp宽度来开发实际显示不全的情况。

而且上述屏幕尺寸、分辨率和像素密度的关系,很多设备并没有按此规则来实现, 因此dpi的值非常乱,没有规律可循,从而导致使用dp适配效果差强人意。

所以我们得从dp和px的转换公式 :px = dp * density 入手

可以看出,如果设计图宽为360dp,想要保证在所有设备计算得出的px值都正好是屏幕宽度的话,我们只能修改 density 的值。

通过阅读源码,我们可以得知,density 是 DisplayMetrics 中的成员变量,而 DisplayMetrics 实例通过Resources#getDisplayMetrics可以获得,而Resouces通过Activity或者Application的Context获得。

先来熟悉下 DisplayMetrics 中和适配相关的几个变量:

DisplayMetrics#density 就是上述的density

DisplayMetrics#densityDpi 就是上述的dpi

DisplayMetrics#scaledDensity字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值

所以我们完全可以修改DisplayMetrics的相关数据来解决问题,

具体使用看UI给的是尺寸  我这边的例子是1280*800然后dpi为160的

剩下的就是根据设计图上面的标注的距离和字体直接填写就好了,

不过注意调用前是在setContentView()前调用

Density.setDensity(this);

Density.setDefault(this);

具体代码demo

具体我借鉴的原文在这  ——字节跳动

其实适配还有很多,这些只是我使用过的,具体呢都是使用步骤,你们要是想了解更实际的得自己深究了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 本篇只介绍最主流的两种屏幕适配方案。 AndroidAutosize 几个基础概念:dp :就...
    杨华_6f65阅读 541评论 0 1
  • 前言 本文为自身的总结与结合其他文章引用而成,分别为: wangwangli6:Android开发:最全面、最易懂...
    ghroost阅读 7,254评论 0 6
  • 目录介绍 1.屏幕适配定义 2.相关重要的概念2.1 屏幕尺寸[物理尺寸]2.2 屏幕分辨率[px]2.3 屏幕像...
    杨充211阅读 1,579评论 0 1
  • 更新:由于该适配方案越来越多人使用,也有很多人遇到不太理解的问题。所以为了大家更好的使用,我将文章很多内容更新了,...
    wildma阅读 231,498评论 355 1,138
  • 感谢这些日子以来喜欢我关注我写作的人,我相信阅读文字这种沟通方式,是比面对面的交流更深情也更能触碰到内心深处...
    Apple树阅读 297评论 0 0