Android 屏幕适配-像素密度适配
说明:本文仅为简单思路,没有实现项目适用的轮子
通过修改系统像素密度做屏幕适配的主要思路是:
通过修改density, scaleDensity, densityDpi值直接更改系统内部对于
目标尺寸而言的像素密度,达到屏幕适配的目的。
名词解释:
-
density:表示屏幕在
一英寸像素点/160 的比值
,如果屏幕在一英寸范围呢的像素点有160个,那么density=1,如果屏幕在一英寸范围呢的像素点有320个,那么density=2
这里xx英寸一般指屏幕对角线
的长度 -
scaleDensity: 表示字体缩放比例,默认scaleDensity =density
-
densityDpi: 表示屏幕上每一英寸的像素点有多少个,就是上述的160,320等值
在Android中,控件呈现到屏幕上的尺寸,最终都会换算成像素为单位,也就是px(无论xml中声明的dp,pt,sp最终都会换算成像素px)
Android xml声明的尺寸单位是在TypedValue
类的applyDimension(int unit, float value, DisplayMetrics metrics)
方法中完成转换的,代码如下
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
从上面的代码中也可以看出,修改DisplayMetrics的 density以及scaledDensity可以影响控件最终的像素值
因为Android 的碎片化现象比较严重,不同的设备density值可能不一样,相同分辨率的设备的density值也有可能不一样
,所以调整或优化处理density的值就是一种Android屏幕适配的方案
我们期望的是density随着屏幕分辨率的变化而变化
,也就是相同分辨率的设备,我们希望density的值是相同的
这种思路实现的屏幕适配比较全面,下面贴下代码,使用的话直接在Activity的setContentView()
方法之前调用即可Density.setDensity(getApplication(),this)
或者在Application中通过registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks())
注册Activity的生命周期监听,在回调方法onActivityCreated(Activity activity, Bundle savedInstanceState)
中调用Density.setDensity(Application.this, activity)
public class Density {
private static final float WIDTH = 320;//参考设备的宽,单位是dp 320 / 2 = 160
private static float appDensity;//表示屏幕密度
private static float appScaleDensity; //字体缩放比例,默认appDensity
public static void setDensity(final Application application, Activity activity){
//获取当前app的屏幕显示信息
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
if (appDensity == 0){
//初始化赋值操作
appDensity = displayMetrics.density;
appScaleDensity = displayMetrics.scaledDensity;
//添加字体变化监听回调
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
//字体发生更改,重新对scaleDensity进行赋值
if (newConfig != null && newConfig.fontScale > 0){
appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
//计算目标值density, scaleDensity, densityDpi
float targetDensity = displayMetrics.widthPixels / WIDTH; // 1080 / 360 = 3.0
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//替换Activity的density, scaleDensity, densityDpi
DisplayMetrics dm = activity.getResources().getDisplayMetrics();
dm.density = targetDensity;
dm.scaledDensity = targetScaleDensity;
dm.densityDpi = targetDensityDpi;
}
}