前言
由于我之前是在一些设备原厂工作的只需要负责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
效果图:
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
具体我借鉴的原文在这 ——字节跳动
其实适配还有很多,这些只是我使用过的,具体呢都是使用步骤,你们要是想了解更实际的得自己深究了