dp、px、dpi的计算公式
- px = density * dp;
- density = dpi / 160;
- px = dp * (dpi / 160);
原理
- UI最终绘制时会把所有尺寸单位(px、dp、sp、pt等)转换成px。
- 选定一种尺寸单位(dp、sp、pt等)作为我们的适配单位,然后篡改这个单位与px之间的转化比例。即更改density(屏幕密度)值。
可以看出,设计图宽为375dp,想要保证在所有设备计算得出的px值都是屏幕宽度的话,只能修改 density 值。
DisplayMetrics
所有的dp和px的转换都是通过 DisplayMetrics 中相关的值来计算的。
布局文件中dp的转换方法如下
TypedValue#applyDimension
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;
}
其他场景的dp转换基本上也都是通过DisplayMetrics来计算的,所以只需要修改 DisplayMetrics 中和dp转换相关的变量即可。
宽维度适配实现
-
px值 = dp值 * metrics.density
。每种手机的px值是固定的,UI会给一套固定的设计图,而且我们要通过这套标注去适配其他手机。为了等式成立只能修改metrics.density
值。
metrics.density = Metrics.widthPixels / 375
- 通过计算出来的density修改dpi
metrics.densityDpi = int(修改后的metrics.density*160);
- 更新sp值,要注意用户可能会更改字体大小
metrics.scaledDensity = 修改后的density * (系统原来的ScaledDensity / 系统原来的Density)
实现代码
private void setCustomDensity(Activity activity, final Application application) {
//application
final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
if (sRoncompatDennsity == 0) {
sRoncompatDennsity = appDisplayMetrics.density;
sRoncompatScaledDensity = appDisplayMetrics.scaledDensity;
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
//计算宽为375dp 同理可以设置高为的根据实际情况
final float targetDensity = appDisplayMetrics.widthPixels / 375;
final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity);
final int targetDensityDpi = (int) (targetDensity * 160);
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
appDisplayMetrics.scaledDensity = targetScaledDensity;
//activity
final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
}
在Activity中调用setContentView()之前调用setCustomDensity()
方法即可。
网友评论