我们在开发过程中,由于android设备碎片化比较严重,各种各样的分辨率的设备都有,想开发出一款好的应用,我们就不得不考虑设备的适配。虽然google官方提供了dp单位来解决不同设备的适配,但在一些特殊的分辨率的设备上是有问题的, 依然不能完美的适配。

首先我们来看一下android中px和dp的转换公式:

px = density * dp;

density = dpi / 160;

px = dp * (dpi / 160);

dpi屏幕像素真实密度,可以通过屏幕对角线的像素点数量/对角线英寸

eg:nexus5手机的分辨率为1920*1080,屏幕尺寸为4.95寸,那么屏幕的真实密度=1920的平方+1080的平方然后在开平方,就可以得到对角线的像素点数(勾股定理)/4.95=445

注意:还有一个是逻辑像素密度dpi,我在做android tv开发的时候,通过打印日志发现海信电视分辨率是1920*1080,dpi=320,显示效果是将原来的界面放大。通过查阅资料和生产厂商沟通才知道,他们系统故意这样设置的。这是故意留给厂家rom定义的,和屏幕像素真实密度有一定的差异,主要是想让分辨率相同但屏幕尺寸不同的设备,显示不同的内容,比如屏幕尺寸大的设备, 可以显示更多的内容。可以通过context.getResources().getDisplayMetrics().densityDpi 可以获取到该值;

通过上面解析知道dpi的值,知道px和dp的转换,同时还可以知道density。

从上面的三个公式我们可以顺利推出。px=dp*density,通过这个公式,我们可以看出,如果想要同一px的值在不同设备上显示效果相同,那么我们只能修改density的值。通过查阅资料或者直接看android源代码,很容易发现density可以通过DisplayMetrics对象获取, DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();

DisplayMetrics 对象有三个属性我们需要注意,density, densityDpi,scaledDensity;

density和densityDpi 这两个属性上面已经解释过了, 那么scaledDensity这个是什么鬼呢?scaledDensity是字体的缩放因子,一般情况下scaledDensity和density是相等的,但如果用户调整了系统字体大小这个值就会发生变化,此时scaledDensity和density就不相等。我们需要注意这一点,不然当用户设置了系统字体,就会发现我们的应用中字体很奇怪。

通过上面的分析,我们可以写一个工具类,主要目的就是计算并设置density, densityDpi,scaledDensity这三个值。

package com.test.demo.utils;import android.app.Activity;import android.content.ComponentCallbacks;import android.content.Context;import android.content.res.Configuration;import android.support.annotation.NonNull;import android.util.DisplayMetrics;/** * 
 * * *-------------------------------------------------------------------* *     scott *                                    江城子 . 程序员之歌 *     /\__/\ *    /`    '\                     十年生死两茫茫,写程序,到天亮。 *  ≈≈≈ 0  0 ≈≈≈ Hello world!          千行代码,Bug何处藏。 *    \  --  /                     纵使上线又怎样,朝令改,夕断肠。 *   /        \                    领导每天新想法,天天改,日日忙。 *  /          \                       相顾无言,惟有泪千行。 * |            |                  每晚灯火阑珊处,夜难寐,加班狂。 *  \  ||  ||  / *   \_oo__oo_/≡≡≡≡≡≡≡≡o * * Created by scott on 2019/7/30. * * *-------------------------------------------------------------------* *  
*/public class ScreenUtils { //这里和设计师协商统一定义一个设计尺寸,这里是1920*1080的分辨率进行设置 private static final float widthdp = 360f; private static final float heightdp = 640f; //记录系统设置的值 private static float systemDensity = 0; private static float systemScaledDensity = 0; public void setCustomDensity(@NonNull final Activity activity) { DisplayMetrics displayMetrics = activity.getApplication().getResources().getDisplayMetrics(); if (systemDensity == 0) { //初始化 systemDensity = displayMetrics.density; systemScaledDensity = displayMetrics.scaledDensity; //添加一个监听,如果用户修改了系统字体,系统就会回掉这个监听 activity.getApplication().registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { systemScaledDensity = activity.getApplication().getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //目标值计算 => px = dp * density final float targetDensity = displayMetrics.widthPixels / widthdp; final float targetScaledDensity = targetDensity * (systemScaledDensity / systemDensity); final int targetDensityDpi = (int) (160 * targetDensity); //设置计算好的值 displayMetrics.density=targetDensity; displayMetrics.scaledDensity=targetScaledDensity; displayMetrics.densityDpi=targetDensityDpi; //设置activity的值 final DisplayMetrics activityDisplayMetrics =activity .getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.scaledDensity = targetScaledDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; }}

使用方法:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //在设置布局之前调用工具类方法        ScreenUtils.setCustomDensity(this);        setContentView(R.layout.activity_main);        int densityDpi = getResources().getDisplayMetrics().densityDpi;        tv.setText("逻辑像素密度 dpi  " + densityDpi);    }}

这样就可以适配不同分辨率的设备了, 通过大量测试,以及用户的反馈,目前没发现有没适配的设备。哈哈

 

上面的内容中,提到过海信的电视分辨率是1920*1080  但dpi=320 ,这种情况我们的项目不能完美的适配设备。如果我们按照上面的方法去设置density和densityDpi,肯说是行不通的。目前想到的方法比较局限,通过后台来控制density和dpi,项目启动的时候,根据后台配置的density 和dpi 来设置DisplayMetrics对应的值,只需设置一次就可以,不需要在每个界面的中设置。这样就可以适配我们的项目。

 

 

 

更多相关文章

  1. Ubuntu上adb找不到设备问题小结
  2. Android 上层应用读写底层设备节点(Android M)
  3. ADB无法找到Android设备
  4. 获取Android设备电池信息
  5. 创建 Android虚拟设备(AVD)
  6. Android设备唯一标识ID的获取
  7. 终于找到一个类似wince 远程桌面控制android设备的软件——Andro
  8. Android 实现缩小图片像素
  9. Android 设备电池容量和使用量的获取

随机推荐

  1. Android(安卓)的 Recovery 分析
  2. Android(安卓)ASE 脚本环境
  3. android中MotionEvent.ACTION_CANCEL事件
  4. 在RelativeLayout布局中可以设置标签的an
  5. android绘图之Paint(1)
  6. 深入Gradle插件开发
  7. android获取正在运行的进程
  8. android中HttpURLConnection调用getRespo
  9. [置顶] android 图标的绘制
  10. 你真的了解你手机的状态栏吗?