屏幕适配:修改屏幕像素密度,随便设dp

前提

平时xml中view的宽高单位都是dp居多,我们的设计师一般会选择一款机型的屏幕尺寸作为设计的目标尺寸。

那么,如何根据目标尺寸的屏幕密度,适配我们种类繁多的机型?

实现目标

将以dp作为单位,以目标尺寸标注的宽高,和当前机型的比例,动态进行屏幕适配。
例如:设计尺寸为360dp宽,我们的view设置180dp宽。那么,该view在任何屏幕尺寸下,都将占用屏幕一半的尺寸;

了解参数

在上代码前,先了解下待会用到的参数含义:

  • density
    当前机型的屏幕密度,标准屏幕密度是每平方英寸有160个像素,如果当前机型每平方英寸有320个像素,即density = (320 / 160)= 2;
  • scaleDensity
    代表的是字体的屏幕密度,默认情况下:scaleDensity = density;
  • densityDpi
    表示的就是每平方英寸显示的像素点个数。
    如:160个像素点 即densityDpi=160;

上代码

代码其实非常简单,直接从DisplayMetrics中获取。

    private final static float WIDTH = 360;//适配机型的宽为360dp,屏幕宽/屏幕密度=360dp

    private static float appDensity;
    private static float appScaleDensity;

    public static void setDensity(Application application, Activity activity) {
        //获取当前app的屏幕显示信息
        DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();

        appDensity = displayMetrics.density;
        appScaleDensity = displayMetrics.scaledDensity;

        //计算等比缩放后的density和scaleDensity
        //WIDTH相对于所有屏幕宽度都是相等的,它是用dp作为单位,所以 屏幕宽度/屏幕密度=WIDTH
        //targetDensity = targetWidht/WIDTH
        float targetDensity = displayMetrics.widthPixels / WIDTH;
        //appScaleDensity/appDensity=targetScaleDensity/targetDensity;
        float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
        int targetDensityDpi = (int) (targetDensity * 160);

        //替换activity的density,appdensity,densityDpi
        DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
        aDisplayMertics.density = targetDensity;
        aDisplayMertics.scaledDensity = targetScaleDensity;
        aDisplayMertics.densityDpi = targetDensityDpi;
    }
}

思路讲解,计算

首先我们需要获取当前机型的屏幕密度信息:appDensity,appScaleDensity

我们的设计尺寸会根据默认机型计算出一个固定的以dp为单位的宽度:WIDTH

比如:默认机型的宽高为1080*1920,该设备的屏幕密度为3
那么WIDTH = 1080/3 = 360dp;因此所有适配机型的宽也就等于360dp。
根据 屏幕宽度 / 屏幕密度=WIDTH公式,现在知道屏幕宽度和WIDTH,也就能求出:屏幕密度=屏幕宽度 / WIDHT;

现在屏幕宽度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。

接下来,就需要求出适配机型的scaleDensity

appScaleDensity / appDensity = targetScaleDensity / targetDensity ;

targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;

densityDpi = density * 160 ;

最后,把获取到的数据,设置到activity的displayMetrics中。

计算出来后,我们需要在绘制view之前先设置好

在onCreate中的setContentView之前添加

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
      //在绘制前设置density
    DensityUtils.setDensity(this.application, this)
    setContentView(R.layout.activity_screen_adapter2)
}

现在,我们的设计尺寸宽度为360dp,我们设置view的宽度为180dp,应该是占用屏幕一半尺寸。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android”
    xmlns:tools=“http://schemas.android.com/tools”
    android:layout_width=“match_parent”
    android:layout_height=“match_parent”
    tools:context=“.screenAdapter2.ScreenAdapter2Activity”>

    <TextView
        android:id=“@+id/tv1”
        android:layout_width=“180dp”
        android:layout_height=“180dp”
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="#f00" />

    <TextView
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:layout_below="@id/tv1"
        android:layout_toRightOf="@id/tv1"
        android:background="#0f0" />

</RelativeLayout>

显示效果:

字体的缩放监听

以上代码在字体发生改变时,不会根据字体设置相应的发生改变
我们需要监听字体改变事件,再重新计算scaleDensity;

//完整代码
public static void setDensity(final Application application, Activity activity) {
    //获取当前app的屏幕显示信息
    DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();

    appDensity = displayMetrics.density;
    appScaleDensity = displayMetrics.scaledDensity;

    //监听字体改变,重新获取scaleDensity
    application.registerComponentCallbacks(new ComponentCallbacks() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            if (newConfig != null && newConfig.fontScale > 0) {
                appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
            }
        }

        @Override
        public void onLowMemory() {

        }
    });

    //计算等比缩放后的density和scaleDensity
    //WIDTH相对于所有屏幕宽度都是相等的,它是用dp作为单位,所以 屏幕宽度/屏幕密度=WIDTH
    //targetDensity = targetWidht/WIDTH
    float targetDensity = displayMetrics.widthPixels / WIDTH;
    //appScaleDensity/appDensity=targetScaleDensity/targetDensity;
    float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
    int targetDensityDpi = (int) (targetDensity * 160);

    //替换activity的density,appdensity,densityDpi
    DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
    aDisplayMertics.density = targetDensity;
    aDisplayMertics.scaledDensity = targetScaleDensity;
    aDisplayMertics.densityDpi = targetDensityDpi;
}

最后

如果你看到了这里,觉得文章写得不错就给个赞呗!欢迎大家评论讨论!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足,定期免费分享技术干货。感兴趣的小伙伴可以点一下关注哦。谢谢!

发布了289 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_45365889/article/details/102660467
今日推荐