最全的屏幕适配方案

xiaoxiao2021-02-28  23

使用

直接在Application的onCreate方法中调用(Density类直接参照附录)

Density.setDensity(this, 375f);

这个地方我们需要注意375f这个参数,针对这个参数,我们来好好说说。

375这个值是一个UI图的参照值,单位是dp,我参照的是1334*750像素的图

然后我们来看下px与dp的转换图

Android单位:dpMDPI1px=1dpHDPI1.5px=1dpXHDPI2px=1dpXXHDPI3px=1dpXXXHDPI4px=1dp

因为我们UI使用的是蓝湖的UI设计,可以根据这些不同的DPI来切换显示不同布局的不同宽度dp值

然后我们继续看那个参数值375,因为我参照的是XHDPI的图进行绘制的,2px=1dp,375这个值就是宽度的像素750px/2px=375dp

然后我们切换到XHDPI进行看看是不是375dp

那么,我们就可以参照上面这个图给出的UI进行设置了,我这个地方给了个测试例子,375dp的话,要想能看出是否精准适配的话,我们可以这样,采用LineaLayout的vertical布局,靠左边设置一个宽度为200dp宽度的widget,靠右设置一个175dp宽度的widget,如果他们两个相交的地方刚好撘上,那么,这就是一个精准的适配

其他几个不同像素的就不展示了,我都测试过了,非常完美解决

对了,还有一个问题,有的UI给出的并不是像我们这种dp方式的,有的UI给的单位是px,其实,这也是很好解决的,比如UI给的是1080*1920的图,那我们就按照XHDPI 2px=1dp的方式来适配,那么,我们设置setDensity的值就为1080/2=540dp,然后UI凡是标注多少px,我们就在布局中给这个px除以2,然后设置到布局上即可

注意:我们在做dp与px换算的时候,尽量保持这个结果dp值在320~560之间,为什么呢?看下面表述

我们看上面的换算表格MDPI 1px=1dp,既然1px=1dp,那么我们怎么不直接给setDensity设置750呢,这样,我还省去了计算,直接参照MDPI的图来做,好,我们就这么来一次,给大家看看效果,最后再来说原因。

参照是750*1334的UI,setDensity的值也设置750,然后设置左widget的宽度为400dp,右边的widget设置375dp,看图

确实能宽度适配,但大家看看,这个字体和页面明显有缩小的感觉,这种适配虽然宽度达到了,但明显不是我们想要的,那是什么原因导致的呢?这时候,我们就要引出一个关键因素像素密度dpi,我来列出两个公式

dp=px/dpi*160 dpi=px*160/dp

这个计算公式是系统通过我们给定xml的值来计算出显示在屏幕上的布局,附录的代码就是利用的这个公式给系统设置计算参数,然后我们把刚刚MDPI适配的方式计算一下dpi

750*160/750=160dpi

160这个密度值明显过低,导致1密度下面占据太多的像素,界面看起来很拥挤,然后我们看下XHDPI的值,750的px等于375dp

750*160/375=320dpi

dpi的值是系统给的,大概查阅了流行的机子的dpi,就是我上面列举的范围内,在我们知道像素宽度的时候,尽量参考Xhdpi来做,这也是我们在适配图片的时候,喜欢参照xhdpi的原因

其实,当我说到这的时候,原因其实差不多也都说出来了,虽然dpi是系统给的,但我们可以通过getDisplayMetrics替换掉这个dpi,上面的公式也给了,我们可以通过getDisplayMetrics拿到widthPixels屏幕的宽度像素值,然后再加上我们通过换算拿到的dp值,那dpi的值也就可以知道了,然后将这些值都设置到系统里面,让系统在解析xml布局的时候,按照我们给他设定的值来计算,然后显示在界面上,这就是适配的原理。


有人说,我是老项目了,如果按照动态这么适配的话,那岂不之前的都要改?确实,但不要担心,还有另一种适配方式,smallWidth适配,修改系统的值属于动态方式来做,那么sw适配方式就属于静态适配了,sw也是根据上面的公式,计算出对应的dp值生成xml,生成xml的java代码也有,是一个哥们做的,大家可以看看他的文章,看这,也挺不错的,计算方式需要自己知道自己适配的机型的dpi,然后通过公式计算出dp值,然后将dp值设置到java代码中,然后运行一下,就可以了,将生成的values放到res文件夹下面就可以了

附录

Application里面调用

@Override public void onCreate() { //记住,这个值需要自己根据UI图计算的哦,可不要直接抄 Density.setDensity(this, 360); }

Density.java

public class Density { private static float appDensity; private static float appScaledDensity; private static DisplayMetrics appDisplayMetrics; /** * 用来参照的的width */ private static float WIDTH; public static void setDensity(@NonNull final Application application, float width) { appDisplayMetrics = application.getResources().getDisplayMetrics(); WIDTH = width; registerActivityLifecycleCallbacks(application); if (appDensity == 0) { //初始化的时候赋值 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() { } }); } } private static void setDefault(Activity activity) { setAppOrientation(activity); } private static void setAppOrientation(@Nullable Activity activity) { float targetDensity = 0; try { targetDensity = appDisplayMetrics.widthPixels / WIDTH; } catch (NumberFormatException e) { e.printStackTrace(); } float targetScaledDensity = targetDensity * (appScaledDensity / appDensity); int targetDensityDpi = (int) (160 * targetDensity); /** * * 最后在这里将修改过后的值赋给系统参数 * * 只修改Activity的density值 */ DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.scaledDensity = targetScaledDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; } private static void registerActivityLifecycleCallbacks(Application application) { application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { setDefault(activity); } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } }); } }
转载请注明原文地址: https://www.6miu.com/read-2000100.html

最新回复(0)